Caché代码规范

版本 内容 日期 作者
V1.0 创建Caché代码规范 2020-03-20 姚鑫,云海宝
V1.1 修改注释空行规范 2020-04-17 姚鑫
V1.2 修改布尔类型方法 2020-05-17 姚鑫
V1.3 增加表结构索引,字段注释 2020-08-25 云海宝

目的

  • 为药房药产品组内部使用。
  • 解决团队内耗,解决争论,统一代码风格。

变量

  1. 代码中的命名均不能 $、%#等特殊符号开始或结束,因为$、%#等是系统方法、变量,禁止混淆。

反例:

  1. $name
  2. _name
  3. %name

正例:

  1. name
  1. 严禁代码中使用拼音与英文混合方式命名,更不允许直接使用中文。

反例:

  1. Dazhe
  2. getPYname
  3. [打折]

正例:

  1. discount
  2. getDispName
  1. 参数名、成员变量、局部变量都统一使用lowerCamelCase风格。

反例:

  1. getname(LocID)
  2. Params

正例:

  1. GetName(locID)
  2. params
  1. 常量命名全部大写。力求完整语义表达清楚,不要嫌长。

反例:

  1. MaxCount = 10

正例:

  1. MAXCOUNT = 10
  1. 杜绝不规范缩写,避免词不达意。

反例:

  1. PIVA
  2. com
  3. condi

正例:

  1. PIVAS
  2. complete
  3. condition
  1. 长度为7个以内单词不需要缩写,当变量长度过长时需考虑缩写,且缩写应为常用正规缩写,避免无意义缩写。

反例:

  1. st
  2. nb

正例:

  1. start
  2. number
  3. num
  1. 避免无意义变量。

反例:

  1. s a="1"
  2. s b="2"
  3. s c=a*b

正例:

  1. s fitstNum = "1"
  2. s secondNum = "2"
  3. s sum = firstNum * secondNum
  1. 临时global、进程global命名严格使用^TMP^||TMP,且携带pid。格式为领域名+ 类名+方法+pid+标识

反例:

  1. s ^||PHA("DHCST",pid,"Login")

正例:

  1. s ^||TMP("PHA",PHA.OP.MOB.Base","Login",pid)
  1. 布尔变量不要用is开头,因为其他框架引用的话会解析错误。例如JavaGetter的方法也叫isDisp()

反例:

  1. isDisp

正例:

  1. dispFlag
  1. 所有表的ID,都用表的前缀。

反例:

  • INC_Itminc
  • DHC_PHARWINphar
  • DHC_PHBoxboxID

正例:

  • INC_Itminci
  • DHC_PHARWINpha
  • DHC_PHBoxphb
  1. 所有引用global数据的变量,用表ID+data方式命名,多节点用ID+节点+Data方式。

反例:

  1. s data=^INCI(inci)
  2. s Data=^INCI(inci)

正例:

  1. s inciData=^INCI(inci)
  1. 方法中仅出现一次dataStr分割字符串分割索引均为i长度均为len,需要多次分割,或同一变量出现多次,参考《约定变量命名》和《约定变量命名字典》。

反例:

  1. s prescNolen=$l(prescNoStr, ",")
  2. f index = 1 : 1 : len q:ret'=0 d
  3. .s prescNo = $p(prescNoStr, ",", index)

正例:

  1. s len = $l(prescNoStr, ",")
  2. f i = 1 : 1 : len q:ret'=0 d
  3. .s prescNo = $p(prescNoStr, ",", i)
  1. 创建的私有对象可以加m,例如有Execute类的初始化对象。

反例:

  1. s execute = ##(PHA.Execute).%New()

正例:

  1. s mExecute = ##(PHA.Execute).%New()
  1. 不要将系统保留字或SQL保留字做为变量。

反例:

  1. s SQLCODE="0"
  2. s SQLTableName=“PHA.OP.Base

正例:

  1. s code="0"
  2. s tableName=“PHA.OP.Base
  1. 对于调用其他方法获取返回值的变量,禁止使用err的名称,推荐ret
  • 目的是解决断错误返回值表示q:ret'=0

反例:

  1. s errRet=##class(PHA.IN.XXX).Save()
  2. s retErr=##class(PHA.IN.XXX).Save()

正例:

  1. s ret=##class(PHA.IN.XXX).Save()
  1. 禁止变量超过31个字符。(局部变量名称限制为31个字符。可以指定长度超过31个字符的名称,但仅使用前31个字符。)

示例:

  1. /// d ##class(PHA.TEST.ObjectScript).TestVarThree()
  2. ClassMethod TestVarThree()
  3. {
  4. s abcdefghiklmnopqrstuvwxzy123456789 = "1"
  5. w abcdefghiklmnopqrstuvwxzy123456789,!
  6. s fitst = 1
  7. s fitstSum = fitst +abcdefghiklmnopqrstuvwxzy123456789
  8. w fitstSum,!
  9. s second = 2
  10. s abcdefghiklmnopqrstuvwxzy1234567891 = "2"
  11. w abcdefghiklmnopqrstuvwxzy1234567891,!
  12. s secondSum = second + abcdefghiklmnopqrstuvwxzy123456789
  13. w secondSum,!
  14. b
  15. }

结果:

  1. DHC-APP>d ##class(PHA.TEST.ObjectScript).TestVarThree()
  2. 1
  3. 2
  4. 2
  5. 4
  6. b }
  7. ^
  8. <BREAK>zTestVarThree+11^PHA.TEST.ObjectScript.1
  9. DHC-APP 2d1>w
  10. <Private variables>
  11. abcdefghiklmnopqrstuvwxzy123456=2
  12. fitst=1
  13. fitstSum=2
  14. second=2
  15. secondSum=4

方法

  1. 类名、方法名使用UpperCamelCase风格。

反例:

  1. PHA.oP.mob.base
  2. getname()

正例:

  1. PHA.OP.MOB.Base
  2. GetName()
  1. 返回布尔类型方法以Is开头,例如是否发药。ture$$$YES,false$$$NO,方法后面加上 As %Boolean.

反例:

  1. GetDispFlag()

正例:

  1. /// 判断明细是否只有一副药
  2. /// w ##class(PHA.OP.MOB.Android).IsSingleHerb("I200713000010")
  3. ClassMethod IsSingleHerb(prescNo) As %Boolean
  4. {
  5. s pii = $o(^BS.PHA.IP.Interim("PrescNo", prescNo, ""))
  6. s itmCount = $o(^BS.PHA.IP.Interim(pii, "I", ""), -1) d
  7. q:itmCount=1 $$$YES
  8. q $$$NO
  9. }

调用:

  1. if(..IsSingleHerb(prescNo)){
  2. // do something
  3. }
  1. q:..IsSingleHerb(prescNo)
  1. q:'..IsSingleHerb(prescNo)
  1. 推荐使用动宾结构,函数名应清晰反应函数的用途和功能。

反例:

  1. ObtainName()

正例:

  1. GetName()
  1. 函数,方法名最长不超过 30 个字符。

反例:

  1. DefineDrugDeliveryProcessEvent()

正例:

  1. SetDispEvent()
  1. 每个方法对应一个词 retrievefetchfindquery 都有查询意思,managerhandlercontroller都有管理之意。我们只规定一种。查询就Query,获取数据就Get

反例:

  1. ObtaionSomething()
  2. RetrieveSomething()

正例:

  1. GetSomething()
  2. QuerySomething()
  1. 一个方法尽量控制在50行(一屏)。如果过于庞大,就该重构。庞大的方法容易引起阅读疲劳,让人抓不住重点。代码逻辑要分主次,个性,共性。

反例:

  1. ClassMethod Login(params)
  2. {
  3. s info =""
  4. f s info = $o(^PHA("info", info)) q:info="" d
  5. .s flag = $p(^PHA("info", info), "^", 1)
  6. .i flag = "Y" d
  7. .sql(insert .....)
  8. }

正例:

  1. ClassMethod Login(params)
  2. {
  3. s info =""
  4. f s info = $o(^PHA("info", info)) q:info="" d
  5. .s flag = $p(^PHA("info", info), "^", 1)
  6. .s ret = ..IsFlag(flag)
  7. }
  8. ClassMethod IsFlag(flag)
  9. {
  10. i flag = "Y" d
  11. .s ..InsSomeThing()
  12. }
  13. ClassMethod InsSomeThing(flag)
  14. {
  15. sql(insert .....)
  16. }
  1. 方法内传递参数过多。考虑用对象方式来重构。

反例:

  1. ClassMethod Login(params)
  2. {
  3. s startDate = $p(params, "^" ,1)
  4. s endDate = $p(params, "^" ,1)
  5. s locID = $p(params, "^" ,1)
  6. s userID = $p(params, "^" ,1)
  7. s groupID = $p(params, "^" ,1)
  8. s ret = ..DoSomeThing(startDate, endDate, locID, userID , groupID)
  9. }
  10. ClassMethod DoSomeThing(startDate, endDate, locID, userID , groupID)
  11. {
  12. s status = $o(^PHA("Flag",flag,""))
  13. s other = $o(^PHA("userID",userID,""))
  14. s flag = $o(^PHA("flag","")
  15. s ret = ..DoSomeThingSub(startDate, endDate, locID, userID , groupID, flag , status, other)
  16. }
  17. ClassMethod DoSomeThing(startDate, endDate, locID, userID , groupID, flag , status, other)
  18. {
  19. //to do
  20. }

正例:

  1. ClassMethod Login(params)
  2. {
  3. s mLogin. = ##class(PHA.OP.MOB.Login).%New(startDate, endDate, locID, userID , groupID)
  4. d mLogin.Login()
  5. }
  6. Class PHA.OP.MOB.Login
  7. {
  8. //各种属性
  9. }
  1. 禁止在循环里直接写sql语句即&sql(),应把sql单独提出成方法。
  • 禁止在公共查询里写涉及存储sql方法。
  • SaveQuery单独建类,分别对应保存与查询的程序,查询程序中不应出现保存的方法。

反例:

  1. ClassMethod Login(params)
  2. {
  3. s info =""
  4. f s info = $o(^PHA("info", info)) q:info="" d
  5. .s flag = $p(^PHA("info", info), "^", 1)
  6. .sql(insert .....)
  7. }

正例:

  1. ClassMethod Login(params)
  2. {
  3. s info =""
  4. f s info = $o(^PHA("info", info)) q:info="" d
  5. .s flag = $p(^PHA("info", info), "^", 1)
  6. .s ret = ..InsSomeThing(flag)
  7. }
  8. ClassMethod InsSomeThing(flag)
  9. {
  10. sql(insert .....)
  11. }
  1. 非普通字符串的入参或返回值需要进行声明,以明确数据类型,如数组、对象、流、引用等。

反例:

  1. /// Description: 入参为引用,返回为数组
  2. classmethod Test(Param)
  3. {
  4. }

正例:

  1. /// Description: 入参为引用,返回为数组
  2. classmethod Test(ByRef param) As %ArrayOfDataTypes
  3. {
  4. }
  1. 当遇错误信息时,返回值不能单纯的返回负数,如无例外,应返回负数^错误信息的格式,不能使用大于等于0的数值作为错误信息的标识
  1. q "-1^代码重复"

  1. 全部类以PHA.XX开头。

反例:

  1. Class DHCST.XXX.XX

正例:

  1. Class PHA.XXX.XX
  1. 所有类里的方法,方法顺序按照常用顺序排序,最常用的最在上,依次。
  2. 类默认均为ProcedureBlock,禁止Not ProcedureBlock,如需使用特殊字符@等,单独建类并定义Not ProcedureBlock

反例:

  1. Class PHA.COM.Status Extends %RegisteredObject [not ProcedureBlock]

正例:

  1. Class PHA.COM.Status Extends %RegisteredObject

表结构

  1. 严格禁止私自修改表结构。
  2. 新增表结构、扩展字段或增加索引,都应先进行表结构申请,填写《表结构扩展申请表》 ,而后发邮件给相关负责人。如果对于新增字段不确定是否需要增加,可联系利润中心或研发组进行确认。
  3. 后续表结构应统一建立为CacheStorage
  4. User命名方式为领域名+产品线+_功能(例如:药库日志PHAIN_Log、门诊发药PHAOP_Disp)。
  5. Global命名方式为类型.领域名.产品线.功能,类型分为如下三种:
    • CT:基础数据,如药品字典、科室等。
    • CF:配置数据,如住院药房科室配置、库存货位等。
    • BS:业务数据,如发药、入库等。
  6. 字段的PropertySqlFieldName应保持一致。
  7. 计数器位于数据Global0节点。
  8. 索引在数据Global最后后缀小写i
  9. 公共表PHAIN开头。
    示例
  1. 基础数据-药库类组
  2. User.PHAINStkCatGrp
  3. PHAIN_StkCatGrp
  4. ^CD.PHA.IN.StkCatGrp
  5. ^CD.PHA.IN.StkCatGrpi(“Code”,SCG_Code,SCG_RowID)
  1. 业务数据-门诊发药
  2. User.PHAOPDisp
  3. PHAOP_Disp
  4. ^BS.PHA.OP.Disp
  5. ^BS.PHA.OP.Dispi("Date"…)
  1. CacheStorage储存结构里 Master Map
    • 存储为类名后面加 D
    • 索引存储类名后面加 I
    • 流存储类名后面加 S
  2. 表结构注释统一使用字段中文含义(简洁明确)。
    反例:
  1. /// PHA_LastTime
  2. Property PHALastTime As %Library.Time [ SqlColumnNumber = 40, SqlFieldName = PHA_LastTime ];

正例:

  1. /// 最近操作时间
  2. Property PHALastTime As %Library.Time [ SqlColumnNumber = 40, SqlFieldName = PHA_LastTime ];

  1. 锁命令应大写全称LOCK
  2. 特别禁止直接锁表结构的Global
  3. 加解锁必须加+-严格控制,否则导致解锁进程内所有锁。
  4. 加锁必须写超时的退出,避免未判断导致异常问题发生,严重时会产生数据错误。
  5. 锁名按PHA+产品线命名,第一个节点为标识,第二节点为唯一的ID,标识为表名时如果有DHCPHAIPPHAIN等前缀需去掉,使用表名的后缀,并且全部大写,除表名外的标识需统一规范,可组内申请。
  • 表名锁:^PHA+产品线(表名,ID)

反例:

  1. LOCK +^PHAOP("OutPhDisp", phd)
  2. LOCK ^PHAIP("PHACOLLECTED", pha)
  3. LOCK +^PHAOP("PHDISPEN"_phd):5 e q err
  4. LOCK +^INCI

正例:

  1. LOCK +^PHAOP("PHDISPEN", phd):5 e q err
  2. LOCK +^PHAIP("PHACOLLECTED", pha):5 e q err
  3. LOCK -^PHAOP("PHDISPEN", phd)
  4. LOCK -^PHAIP("PHACOLLECTED", pha)
  • 功能锁:^PHA+产品线(规范代码,唯一标识)(如锁处方号、物流箱号等)

反例:

  1. LOCK +^DHCSTLOCK(lockName)
  2. LOCK +^TMPOP(lockName)
  3. l +^IP(lockName)
  4. l +^INCI
  5. l ^TMPOP(lockName)

正例:

  1. LOCK +^PHAOP("BOXNO" + boxNo):5 e q err
  2. LOCK +^PHAIP("PRESCNO" + prescNo):5 e q err

事务

  1. 严格禁止开放性事务,事务tstctro的位置应保持近距离,避免位置过远。
  2. 严格禁止跨方法提交事务。
  3. 为明确显示事务,事务命令需要简写并且小写

反例:

  1. ClassMethod SaveSomething()
  2. {
  3. TSTART
  4. ...
  5. TCOMMIT
  6. }

正例:

  1. ClassMethod SaveSomething()
  2. {
  3. ts
  4. ...
  5. tc
  6. }
  1. 因事务的原理,不宜嵌套,且同一个方法内不应该出现事务嵌套的现象。
  2. 事务应在保存程序的最外层,单一的数据不保存不需要事务。
  3. ts,tc 首尾添加空行,或者注释.。

反例:

  1. ClassMethod Save()
  2. {
  3. TSTART
  4. s ret=..SaveMain()
  5. ...
  6. s retItm=..SaveDetail()
  7. ...
  8. TCOMMIT
  9. }
  10. ClassMethod SaveMain()
  11. {
  12. TSTART
  13. ...
  14. TCOMMIT
  15. }
  16. ClassMethod SaveDetail()
  17. {
  18. TSTART
  19. ...
  20. TCOMMIT
  21. }

正例:

  1. ClassMethod Save()
  2. {
  3. ts
  4. s ret=..SaveMain()
  5. i ret<0 tro q
  6. ...
  7. s ret=..SaveDetail()
  8. i ret<0 tro q
  9. ...
  10. tc
  11. }
  12. ClassMethod SaveMain()
  13. {
  14. ...
  15. }
  16. ClassMethod SaveDetail()
  17. {
  18. ...
  19. }

陷阱

  1. 严格禁止陷阱内部报错导致死进程。
  2. 陷阱名称统一为 Err+方法名,除公共陷阱DHCSTERROR.mac外,其他陷阱都应在对应方法中。

反例:

  1. ClassMethod SaveSomething()
  2. {
  3. s $zt="SaveSomething"
  4. ...
  5. SaveSomething
  6. ...
  7. }

正例:

  1. ClassMethod SaveSomething()
  2. {
  3. s $zt="ErrSaveSomething"
  4. ...
  5. ErrSaveSomething
  6. ...
  7. }

格式

  1. 方法大括号一律换行显示。

反例:

  1. SetDispEvent(){
  2. }

正例:

  1. SetDispEvent()
  2. {
  3. }
  1. 以下符号添加空格,美观代码,=+-*/_: 左右加空格,,之后加空格 。

反例:

  1. GetName(hour,number,year)
  2. {
  3. s name=“yaoxin
  4. s day=hour*number
  5. s sub=$o(^PHA("DATE",day,hour,""))
  6. }

正例:

  1. GetName(hour, number, year)
  2. {
  3. s name = yaoxin
  4. s day = hour * number
  5. s sub = $o(^PHA("DATE", day, hour, ""))
  6. }
  1. 方法内命令行均采用一个制表符tab缩进,宽度为四个空格宽度。注意是一个tab键,而不是按四次空格,可在studio设置(默认为4)

反例:

  1. GetName(hour,number)
  2. {
  3. s name=“yaoxin
  4. s day=hour*number
  5. s sub=$o(^PHA("DATE",day,hour,""))
  6. }

正例:

  1. GetName(hour, number)
  2. {
  3. s name = yaoxin
  4. s day = hour * number
  5. s sub = $o(^PHA("DATE", day, hour, ""))
  6. }
  1. SQL语句一行5个字段。并且换行后3个tab键为准。逗号在每行行末,不要带入下行开始。因为一行字符书不超过120个,即一屏。

反例:

  1. ClassMethod InsBox(str As %String) As %Library.String
  2. {
  3. &SQL(Insert Into DHC_PHBox (
  4. PHB_No, PHB_Num, PHB_Status, PHB_FLoc_Dr,PHB_TLoc_Dr,PHB_UserCreate_Dr,PHB_DateCreate, PHB_TimeCreate, PHB_PrintFlag, PHB_Remark)
  5. values(
  6. :boxNo, 1, :status, :fromLocID, :toLocID,:userID, :date, :time, "Y", :remark))
  7. q SQLCODE
  8. }

正例:

  1. ClassMethod InsBox(str As %String) As %Library.String
  2. {
  3. &SQL(Insert Into DHC_PHBox (
  4. PHB_No, PHB_Num, PHB_Status, PHB_FLoc_Dr, PHB_TLoc_Dr,
  5. PHB_UserCreate_Dr, PHB_DateCreate, PHB_TimeCreate, PHB_PrintFlag, PHB_Remark)
  6. values(
  7. :boxNo, 1, :status, :fromLocID, :toLocID,
  8. :userID, :date, :time, "Y", :remark))
  9. q SQLCODE
  10. }
  1. 单行字符串拼写最多5个字段。因为一行字符书不超过120个,即一屏。

反例:

  1. ClassMethod GetString(str As %String) As %Library.String
  2. {
  3. s str = first _ second _third _ fourth _ fifth _six
  4. }

正例:

  1. ClassMethod InsBox(str As %String) As %Library.String
  2. {
  3. s str = first _ second _third _ fourth _ fifth
  4. s str = str _ six
  5. }
  1. 禁止用同一变量后加数字累加。

反例:

  1. ClassMethod GetString(str As %String) As %Library.String
  2. {
  3. s str1 = first _ second _ third _ fourth _ fifth
  4. s str2 = six
  5. s str = str1 _ str2
  6. }

正例:

  1. ClassMethod InsBox(str As %String) As %Library.String
  2. {
  3. s str = first _ second _ third _ fourth _ fifth
  4. s str = str _ six
  5. }
  1. 获取多返回值用数组%ArrayOfDataTypes

反例:

  1. ClassMethod GetPatLocDesc(prescNo)
  2. {
  3. s str = wardID _ wardLocDR _ patLocDesc
  4. q str
  5. }

正例:

  1. ClassMethod GetPatLocDesc(prescNo)
  2. {
  3. s array=##class(%ArrayOfDataTypes).%New()
  4. d array.SetAt(wardID,"wardID")
  5. d array.SetAt(wardLocDR,"wardLocDR")
  6. d array.SetAt(patLocDesc,"patLocDesc")
  7. q array
  8. }
  1. 禁止系统命名混搭方法中出现sset 统一用命名缩写方式。

反例:

  1. ClassMethod GetPatLocDesc(prescNo)
  2. {
  3. s str = wardID
  4. set patLocDesc = “病区”
  5. do ..GetName()
  6. q str
  7. }

正例:

  1. ClassMethod GetPatLocDesc(prescNo)
  2. {
  3. s str = wardID
  4. s patLocDesc = “病区”
  5. d ..GetName()
  6. q str
  7. }
  1. 禁止命令出现大小写,统一小写。

反例:

  1. ClassMethod GetName(userID)
  2. {
  3. s name=“yaoxin
  4. S age=30
  5. }

正例:

  1. ClassMethod GetName(userID)
  2. {
  3. s name = yaoxin
  4. s age = 30
  5. }
  1. 尽量使用对仗词。
  1. add/remove
  2. open/close
  3. get/set
  4. start/end
  5. insert/delete
  6. show/hide
  7. lock/unlock
  8. first/last
  9. next/previous
  10. old/new
  1. 禁止{}.同时出现,推荐用使用块级语法,抛弃使用点语法。

反例:

  1. ClassMethod GetName(userID)
  2. {
  3. i flag="yx" d
  4. .i other = "other"{
  5. s name = other
  6. }
  7. .s name = "yx"
  8. }

正例:

  1. ClassMethod GetName(userID)
  2. {
  3. i flag="yx" {
  4. i other = "other" {
  5. s name = other
  6. }
  7. s name = "yx"
  8. }
  9. }
  1. 如果if语句只有一行,建议使用三元运算符。所有if语句都要换行写加d写,即使只有一行

反例:

  1. i name="yx" s age=30
  2. e s age=0

正例:1

  1. i name = "yx" d
  2. .s age = 30
  3. e d
  4. .s age =0

正例:2

  1. s age = $s(name = "yx" : age = "30", 1 : "")
  1. if 嵌套不宜过多,建议不超过3层。

反例:

  1. i name = "yx" d
  2. .s state = 30
  3. .i gender = "男" d
  4. ..s state = 20
  5. ..i age = "年轻人"
  6. ...s state = 10
  7. e d
  8. .s state =0

正例:用策略模式或状态模式封装

  1. 多级if else 考虑用@case替换。

反例:

  1. i day =1 d
  2. .s desc = "Monday"
  3. e i day =2 d
  4. .s desc = "Tuesday"
  5. e i day =3 d
  6. .s desc = "Wednesday"

正例:

  1. $CASE(day,
  2. 1:"Monday",
  3. 2:"Tuesday",
  4. 3:"Wednesday",
  5. 4:"Thursday",
  6. 5:"Friday",
  7. 6:"Saturday",
  8. 7:"Sunday",
  9. :"entry error"
  10. )
  1. 与或逻辑运算统一使用&&||,禁止使用其他&!,

反例:

  1. s firstName = "Yao"
  2. s lastNmae = "Xin"
  3. i firstName = "Yao",lastNmae = "Xin" d
  4. .w "true",!
  5. e d
  6. .w "false",!

正例:

  1. s firstName = "Yao"
  2. s lastNmae = "Xin"
  3. i (firstName = "Yao")&&(lastNmae = "Xin") d
  4. .w "true",!
  5. e d
  6. .w "false",!

空行

  1. 方法与方法之间进行空行隔断。(1个空行)

反例:

  1. Method GetName()
  2. {
  3. ...
  4. }
  5. Method GetAge()
  6. {
  7. ...
  8. }

正例:

  1. Method GetName()
  2. {
  3. ...
  4. }
  5. Method GetAge()
  6. {
  7. ...
  8. }
  1. 空行用来分割功能相似,逻辑内容,意思相近的代码片段,使程序布局更加清晰。

反例:

  1. ClassMethod Execute(params)
  2. {
  3. s $zt="ErrExecute"
  4. s prescNo = $p(params, ..#Del, 1)
  5. s exeCode = $p(params, ..#Del, 2)
  6. s userID = $p(params, ..#Del, 3)
  7. s locID = $p(params, ..#Del, 4)
  8. TSTART
  9. s mExecute = ##class(PHA.DEC.MOB.Execute).%New(prescNo, exeCode, userID, locID)
  10. s ret = mExecute.Execute()
  11. i ret'=0 TROLLBACK
  12. q:ret'=0 ..RetFail(ret)
  13. TCOMMIT
  14. s rows = ..GetPrescDetail(prescNo)
  15. s objectJson = ..GetPrescData(prescNo)
  16. s objectJson.rows = rows
  17. q ..RetObject(objectJson)
  18. ErrExecute
  19. q ..RetFail($ze)
  20. }

正例:

  1. ClassMethod Execute(params)
  2. {
  3. s $zt="ErrExecute"
  4. s prescNo = $p(params, ..#Del, 1)
  5. s exeCode = $p(params, ..#Del, 2)
  6. s userID = $p(params, ..#Del, 3)
  7. s locID = $p(params, ..#Del, 4)
  8. TSTART
  9. s mExecute = ##class(PHA.DEC.MOB.Execute).%New(prescNo, exeCode, userID, locID)
  10. s ret = mExecute.Execute()
  11. i ret'=0 TROLLBACK
  12. q:ret'=0 ..RetFail(ret)
  13. TCOMMIT
  14. s rows = ..GetPrescDetail(prescNo)
  15. s objectJson = ..GetPrescData(prescNo)
  16. s objectJson.rows = rows
  17. q ..RetObject(objectJson)
  18. ErrExecute
  19. q ..RetFail($ze)
  20. }
  1. 基于第2点,空行之前添加行注释也要空行,并且行注释/* 规则 */
    注意:*号后有一个空格。

反例:

  1. ClassMethod Execute(params)
  2. {
  3. s $zt="ErrExecute"
  4. s prescNo = $p(params, ..#Del, 1)
  5. s exeCode = $p(params, ..#Del, 2)
  6. s userID = $p(params, ..#Del, 3)
  7. s locID = $p(params, ..#Del, 4)
  8. TSTART
  9. s mExecute = ##class(PHA.DEC.MOB.Execute).%New(prescNo, exeCode, userID, locID)
  10. s ret = mExecute.Execute()
  11. i ret'=0 TROLLBACK
  12. q:ret'=0 ..RetFail(ret)
  13. TCOMMIT
  14. s rows = ..GetPrescDetail(prescNo)
  15. s objectJson = ..GetPrescData(prescNo)
  16. s objectJson.rows = rows
  17. q ..RetObject(objectJson)
  18. ErrExecute
  19. q ..RetFail($ze)
  20. }

正例:

  1. ClassMethod Execute(params)
  2. {
  3. s $zt="ErrExecute"
  4. /* 获取入参 */
  5. s prescNo = $p(params, ..#Del, 1)
  6. s exeCode = $p(params, ..#Del, 2)
  7. s userID = $p(params, ..#Del, 3)
  8. s locID = $p(params, ..#Del, 4)
  9. /* 执行方法 */
  10. TSTART
  11. s mExecute = ##class(PHA.DEC.MOB.Execute).%New(prescNo, exeCode, userID, locID)
  12. s ret = mExecute.Execute()
  13. i ret'=0 TROLLBACK
  14. q:ret'=0 ..RetFail(ret)
  15. TCOMMIT
  16. /* 获取json */
  17. s rows = ..GetPrescDetail(prescNo)
  18. s objectJson = ..GetPrescData(prescNo)
  19. s objectJson.rows = rows
  20. /* 返回json */
  21. q ..RetObject(objectJson)
  22. ErrExecute
  23. q ..RetFail($ze)
  24. }
  1. 事务首尾先后一定要加空行或注释,代表强调。

反例:

  1. Method SaveSomething(params)
  2. {
  3. s ret
  4. ts
  5. ...//to do
  6. tc
  7. q ret
  8. }

正例:

  1. Method GetName()
  2. {
  3. s ret
  4. ts
  5. ...//to do
  6. tc
  7. q ret
  8. }

注释

  1. 句首注释用/* */ ,句尾注释用// ,头注释用/// ,注意各类注释后应跟空格

反例:

  1. // desc: 获取名称
  2. ///Input: 用户ID
  3. ClassMethod GetName(userID)
  4. {
  5. //获取参数
  6. s userID = $p(params, "#", 1) ;用户ID
  7. }

正例:

  1. /// Description: 获取名称
  2. ClassMethod GetName(params)
  3. {
  4. /* 获取参数 */
  5. s userID = $p(params, "#", 1) // 用户ID
  6. }
  1. 避免无意义注释,尽量用规范的代码命名语言去描述。不要浪费大量时间在毫无意义的注释上。简明扼要,不要啰嗦,注释应当画龙点睛。

反例:

  1. /// Description: 获取名称
  2. /// Input: 用户ID
  3. ClassMethod GetName(userID)
  4. {
  5. }

正例:无须注释

  1. ClassMethod GetName(userID)
  2. {
  3. }
  1. 所有类加上创建者和日期,创建者应为姓名的全拼,避免出现yx等简写或其他英文名,并简易说明类用途。

反例:

  1. Class PHA.DEC.MOB.API Extends PHA.DEC.MOB.Business

正例:

  1. /// Description: 煎药室接口
  2. /// Creator: yaoxin
  3. /// CreateDate: 2020-03-11
  4. Class PHA.DEC.MOB.API Extends PHA.DEC.MOB.Business
  1. 避免错误注释误导。可能由于复制过来方法,没有改注释。这样的注释后期开发人员困惑性极大。

反例:

  1. /// Description: 获取年龄
  2. /// Input: 科室ID
  3. ClassMethod GetName(userID)
  4. {
  5. }

正例:

  1. ClassMethod GetName(userID)
  2. {
  3. }
  1. 方法的完整注释,关于接口中的方法以及存储数据核心方法(如门诊发药),应给与完整注释以及修改记录等。
  1. /// Description: 住院是否存在未退药,提前退费已退
  2. /// Creator: xingming
  3. /// CreateDate: 2019-04-03
  4. /// Table: 涉及的表,普通查询可不写,视方法核心等级
  5. /// Input: DspId(打包表Id)
  6. /// Output: 输出说明
  7. /// Return: 1(已退),0(存在未退申请)
  8. /// Version: V7~V8.3+
  9. /// Caller: 护士站,需关注医嘱调用(转科,出院)
  10. /// Modify: 增加急诊留观判断,2020-02-01,xingming
  11. /// Debug: w ##class(PHA.FACE.OUT.Com).IfIPUnReturn(780)
  1. 类和方法注释 保持对齐公正。

反例:

  1. /// Description: 住院是否存在未退药,提前退费已退
  2. /// Creator: xingming
  3. /// CreateDate: 2019-04-03
  4. /// Table:涉及的表,普通查询可不写,视方法核心等级
  5. /// Input:DspId(打包表Id)
  6. /// Output: 输出说明
  7. /// Return: 1(已退),0(存在未退申请)
  8. /// Version: V7~V8.3+
  9. /// Caller: 护士站,需关注医嘱调用(转科,出院)
  10. /// Modify: 增加急诊留观判断,2020-02-01,xingming
  11. /// Debug: w ##class(PHA.FACE.OUT.Com).IfIPUnReturn(780)

正例:

  1. /// Description: 住院是否存在未退药,提前退费已退
  2. /// Creator: xingming
  3. /// CreateDate: 2019-04-03
  4. /// Table: 涉及的表,普通查询可不写,视方法核心等级
  5. /// Input: DspId(打包表Id)
  6. /// Output: 输出说明
  7. /// Return: 1(已退),0(存在未退申请)
  8. /// Version: V7~V8.3+
  9. /// Caller: 护士站,需关注医嘱调用(转科,出院)
  10. /// Modify: 增加急诊留观判断,2020-02-01,xingming
  11. /// Debug: w ##class(PHA.FACE.OUT.Com).IfIPUnReturn(780)

其他说明

  1. 已发布或调试完的程序中不应该再出现断点b,调试后及时清除。
  2. 禁止在涉及大量数据统计的程序中,使用不包含TMPGlobal
  3. 常用变量参考《变量字典》禁止其他以外命名方式命名。
  4. 产品组命名规范参考《产品命名及路径.V1》。