Caché代码规范
版本 | 内容 | 日期 | 作者 |
---|---|---|---|
V1.0 | 创建Caché代码规范 | 2020-03-20 | 姚鑫,云海宝 |
V1.1 | 修改注释空行规范 | 2020-04-17 | 姚鑫 |
V1.2 | 修改布尔类型方法 | 2020-05-17 | 姚鑫 |
V1.3 | 增加表结构索引,字段注释 | 2020-08-25 | 云海宝 |
目的
- 为药房药产品组内部使用。
- 解决团队内耗,解决争论,统一代码风格。
变量
- 代码中的命名均不能 $、
%
、#
等特殊符号开始或结束,因为$、%
、#
等是系统方法、变量,禁止混淆。
反例:
$name
_name
%name
正例:
name
- 严禁代码中使用拼音与英文混合方式命名,更不允许直接使用中文。
反例:
Dazhe
getPYname
[打折]
正例:
discount
getDispName
- 参数名、成员变量、局部变量都统一使用
lowerCamelCase
风格。
反例:
getname(LocID)
Params
正例:
GetName(locID)
params
- 常量命名全部大写。力求完整语义表达清楚,不要嫌长。
反例:
MaxCount = 10
正例:
MAXCOUNT = 10
- 杜绝不规范缩写,避免词不达意。
反例:
PIVA
com
condi
正例:
PIVAS
complete
condition
- 长度为7个以内单词不需要缩写,当变量长度过长时需考虑缩写,且缩写应为常用正规缩写,避免无意义缩写。
反例:
st
nb
正例:
start
number
num
- 避免无意义变量。
反例:
s a="1"
s b="2"
s c=a*b
正例:
s fitstNum = "1"
s secondNum = "2"
s sum = firstNum * secondNum
- 临时
global
、进程global
命名严格使用^TMP
、^||TMP
,且携带pid
。格式为领域名+ 类名+方法+pid+标识
。
反例:
s ^||PHA("DHCST",pid,"Login")
正例:
s ^||TMP("PHA",PHA.OP.MOB.Base","Login",pid)
- 布尔变量不要用
is
开头,因为其他框架引用的话会解析错误。例如Java
的Getter
的方法也叫isDisp()
。
反例:
isDisp
正例:
dispFlag
- 所有表的
ID
,都用表的前缀。
反例:
INC_Itm
:inc
DHC_PHARWIN
:phar
DHC_PHBox
:boxID
正例:
INC_Itm
:inci
DHC_PHARWIN
:pha
DHC_PHBox
:phb
- 所有引用
global
数据的变量,用表ID+data方式命名,多节点用ID+节点+Data
方式。
反例:
s data=^INCI(inci)
s Data=^INCI(inci)
正例:
s inciData=^INCI(inci)
- 方法中仅出现一次
dataStr
分割字符串分割索引均为i
长度均为len
,需要多次分割,或同一变量出现多次,参考《约定变量命名》和《约定变量命名字典》。
反例:
s prescNolen=$l(prescNoStr, ",")
f index = 1 : 1 : len q:ret'=0 d
.s prescNo = $p(prescNoStr, ",", index)
正例:
s len = $l(prescNoStr, ",")
f i = 1 : 1 : len q:ret'=0 d
.s prescNo = $p(prescNoStr, ",", i)
- 创建的私有对象可以加
m
,例如有Execute
类的初始化对象。
反例:
s execute = ##(PHA.Execute).%New()
正例:
s mExecute = ##(PHA.Execute).%New()
- 不要将系统保留字或
SQL
保留字做为变量。
反例:
s SQLCODE="0"
s SQLTableName=“PHA.OP.Base”
正例:
s code="0"
s tableName=“PHA.OP.Base”
- 对于调用其他方法获取返回值的变量,禁止使用
err
的名称,推荐ret
。
- 目的是解决断错误返回值表示
q:ret'=0
反例:
s errRet=##class(PHA.IN.XXX).Save()
s retErr=##class(PHA.IN.XXX).Save()
正例:
s ret=##class(PHA.IN.XXX).Save()
- 禁止变量超过31个字符。(局部变量名称限制为31个字符。可以指定长度超过31个字符的名称,但仅使用前31个字符。)
示例:
/// d ##class(PHA.TEST.ObjectScript).TestVarThree()
ClassMethod TestVarThree()
{
s abcdefghiklmnopqrstuvwxzy123456789 = "1"
w abcdefghiklmnopqrstuvwxzy123456789,!
s fitst = 1
s fitstSum = fitst +abcdefghiklmnopqrstuvwxzy123456789
w fitstSum,!
s second = 2
s abcdefghiklmnopqrstuvwxzy1234567891 = "2"
w abcdefghiklmnopqrstuvwxzy1234567891,!
s secondSum = second + abcdefghiklmnopqrstuvwxzy123456789
w secondSum,!
b
}
结果:
DHC-APP>d ##class(PHA.TEST.ObjectScript).TestVarThree()
1
2
2
4
b }
^
<BREAK>zTestVarThree+11^PHA.TEST.ObjectScript.1
DHC-APP 2d1>w
<Private variables>
abcdefghiklmnopqrstuvwxzy123456=2
fitst=1
fitstSum=2
second=2
secondSum=4
方法
- 类名、方法名使用
UpperCamelCase
风格。
反例:
PHA.oP.mob.base
getname()
正例:
PHA.OP.MOB.Base
GetName()
- 返回布尔类型方法以
Is
开头,例如是否发药。ture
为$$$YES
,false
为$$$NO
,方法后面加上As %Boolean
.
反例:
GetDispFlag()
正例:
/// 判断明细是否只有一副药
/// w ##class(PHA.OP.MOB.Android).IsSingleHerb("I200713000010")
ClassMethod IsSingleHerb(prescNo) As %Boolean
{
s pii = $o(^BS.PHA.IP.Interim("PrescNo", prescNo, ""))
s itmCount = $o(^BS.PHA.IP.Interim(pii, "I", ""), -1) d
q:itmCount=1 $$$YES
q $$$NO
}
调用:
if(..IsSingleHerb(prescNo)){
// do something
}
q:..IsSingleHerb(prescNo)
q:'..IsSingleHerb(prescNo)
- 推荐使用动宾结构,函数名应清晰反应函数的用途和功能。
反例:
ObtainName()
正例:
GetName()
- 函数,方法名最长不超过 30 个字符。
反例:
DefineDrugDeliveryProcessEvent()
正例:
SetDispEvent()
- 每个方法对应一个词
retrieve
、fetch
、find
、query
都有查询意思,manager
、handler
、controller
都有管理之意。我们只规定一种。查询就Query
,获取数据就Get
。
反例:
ObtaionSomething()
RetrieveSomething()
正例:
GetSomething()
QuerySomething()
- 一个方法尽量控制在50行(一屏)。如果过于庞大,就该重构。庞大的方法容易引起阅读疲劳,让人抓不住重点。代码逻辑要分主次,个性,共性。
反例:
ClassMethod Login(params)
{
s info =""
f s info = $o(^PHA("info", info)) q:info="" d
.s flag = $p(^PHA("info", info), "^", 1)
.i flag = "Y" d
.sql(insert .....)
}
正例:
ClassMethod Login(params)
{
s info =""
f s info = $o(^PHA("info", info)) q:info="" d
.s flag = $p(^PHA("info", info), "^", 1)
.s ret = ..IsFlag(flag)
}
ClassMethod IsFlag(flag)
{
i flag = "Y" d
.s ..InsSomeThing()
}
ClassMethod InsSomeThing(flag)
{
sql(insert .....)
}
- 方法内传递参数过多。考虑用对象方式来重构。
反例:
ClassMethod Login(params)
{
s startDate = $p(params, "^" ,1)
s endDate = $p(params, "^" ,1)
s locID = $p(params, "^" ,1)
s userID = $p(params, "^" ,1)
s groupID = $p(params, "^" ,1)
s ret = ..DoSomeThing(startDate, endDate, locID, userID , groupID)
}
ClassMethod DoSomeThing(startDate, endDate, locID, userID , groupID)
{
s status = $o(^PHA("Flag",flag,""))
s other = $o(^PHA("userID",userID,""))
s flag = $o(^PHA("flag","")
s ret = ..DoSomeThingSub(startDate, endDate, locID, userID , groupID, flag , status, other)
}
ClassMethod DoSomeThing(startDate, endDate, locID, userID , groupID, flag , status, other)
{
//to do
}
正例:
ClassMethod Login(params)
{
s mLogin. = ##class(PHA.OP.MOB.Login).%New(startDate, endDate, locID, userID , groupID)
d mLogin.Login()
}
Class PHA.OP.MOB.Login
{
//各种属性
}
- 禁止在循环里直接写
sql
语句即&sql()
,应把sql
单独提出成方法。
- 禁止在公共查询里写涉及存储
sql
方法。 Save
、Query
单独建类,分别对应保存与查询的程序,查询程序中不应出现保存的方法。
反例:
ClassMethod Login(params)
{
s info =""
f s info = $o(^PHA("info", info)) q:info="" d
.s flag = $p(^PHA("info", info), "^", 1)
.sql(insert .....)
}
正例:
ClassMethod Login(params)
{
s info =""
f s info = $o(^PHA("info", info)) q:info="" d
.s flag = $p(^PHA("info", info), "^", 1)
.s ret = ..InsSomeThing(flag)
}
ClassMethod InsSomeThing(flag)
{
sql(insert .....)
}
- 非普通字符串的入参或返回值需要进行声明,以明确数据类型,如数组、对象、流、引用等。
反例:
/// Description: 入参为引用,返回为数组
classmethod Test(Param)
{
}
正例:
/// Description: 入参为引用,返回为数组
classmethod Test(ByRef param) As %ArrayOfDataTypes
{
}
- 当遇错误信息时,返回值不能单纯的返回负数,如无例外,应返回
负数^错误信息的格式
,不能使用大于等于0的数值作为错误信息的标识
q "-1^代码重复"
类
- 全部类以
PHA.XX
开头。
反例:
Class DHCST.XXX.XX
正例:
Class PHA.XXX.XX
- 所有类里的方法,方法顺序按照常用顺序排序,最常用的最在上,依次。
- 类默认均为
ProcedureBlock
,禁止Not ProcedureBlock
,如需使用特殊字符@等,单独建类并定义Not ProcedureBlock
。
反例:
Class PHA.COM.Status Extends %RegisteredObject [not ProcedureBlock]
正例:
Class PHA.COM.Status Extends %RegisteredObject
表结构
- 严格禁止私自修改表结构。
- 新增表结构、扩展字段或增加索引,都应先进行表结构申请,填写《表结构扩展申请表》 ,而后发邮件给相关负责人。如果对于新增字段不确定是否需要增加,可联系利润中心或研发组进行确认。
- 后续表结构应统一建立为
CacheStorage
。 User
命名方式为领域名+产品线+_功能
(例如:药库日志PHAIN_Log
、门诊发药PHAOP_Disp
)。Global
命名方式为类型.领域名.产品线.功能
,类型分为如下三种:CT
:基础数据,如药品字典、科室等。CF
:配置数据,如住院药房科室配置、库存货位等。BS
:业务数据,如发药、入库等。
- 字段的
Property
与SqlFieldName
应保持一致。 - 计数器位于数据
Global
的0
节点。 - 索引在数据Global最后后缀小写
i
。 - 公共表
PHAIN
开头。
示例
基础数据-药库类组
User.PHAINStkCatGrp
PHAIN_StkCatGrp
^CD.PHA.IN.StkCatGrp
^CD.PHA.IN.StkCatGrpi(“Code”,SCG_Code,SCG_RowID)
业务数据-门诊发药
User.PHAOPDisp
PHAOP_Disp
^BS.PHA.OP.Disp
^BS.PHA.OP.Dispi("Date"…)
CacheStorage
储存结构里Master Map
。- 存储为类名后面加
D
。 - 索引存储类名后面加
I
。 - 流存储类名后面加
S
。
- 存储为类名后面加
- 表结构注释统一使用字段中文含义(简洁明确)。
反例:
/// PHA_LastTime
Property PHALastTime As %Library.Time [ SqlColumnNumber = 40, SqlFieldName = PHA_LastTime ];
正例:
/// 最近操作时间
Property PHALastTime As %Library.Time [ SqlColumnNumber = 40, SqlFieldName = PHA_LastTime ];
锁
- 锁命令应大写全称
LOCK
- 特别禁止直接锁表结构的
Global
- 加解锁必须加
+
、-
严格控制,否则导致解锁进程内所有锁。 - 加锁必须写超时的退出,避免未判断导致异常问题发生,严重时会产生数据错误。
- 锁名按
PHA+产品线命名
,第一个节点为标识
,第二节点为唯一的ID
,标识为表名时如果有DHC
、PHAIP
、PHAIN
等前缀需去掉,使用表名的后缀,并且全部大写,除表名外的标识需统一规范,可组内申请。
- 表名锁:
^PHA+产品线(表名,ID)
反例:
LOCK +^PHAOP("OutPhDisp", phd)
LOCK ^PHAIP("PHACOLLECTED", pha)
LOCK +^PHAOP("PHDISPEN"_phd):5 e q err
LOCK +^INCI
正例:
LOCK +^PHAOP("PHDISPEN", phd):5 e q err
LOCK +^PHAIP("PHACOLLECTED", pha):5 e q err
LOCK -^PHAOP("PHDISPEN", phd)
LOCK -^PHAIP("PHACOLLECTED", pha)
- 功能锁:
^PHA+产品线(规范代码,唯一标识)
(如锁处方号、物流箱号等)
反例:
LOCK +^DHCSTLOCK(lockName)
LOCK +^TMPOP(lockName)
l +^IP(lockName)
l +^INCI
l ^TMPOP(lockName)
正例:
LOCK +^PHAOP("BOXNO" + boxNo):5 e q err
LOCK +^PHAIP("PRESCNO" + prescNo):5 e q err
事务
- 严格禁止开放性事务,事务
ts
、tc
、tro
的位置应保持近距离,避免位置过远。 - 严格禁止跨方法提交事务。
- 为明确显示事务,事务命令需要简写并且小写。
反例:
ClassMethod SaveSomething()
{
TSTART
...
TCOMMIT
}
正例:
ClassMethod SaveSomething()
{
ts
...
tc
}
- 因事务的原理,不宜嵌套,且同一个方法内不应该出现事务嵌套的现象。
- 事务应在保存程序的最外层,单一的数据不保存不需要事务。
ts
,tc
首尾添加空行
,或者注释
.。
反例:
ClassMethod Save()
{
TSTART
s ret=..SaveMain()
...
s retItm=..SaveDetail()
...
TCOMMIT
}
ClassMethod SaveMain()
{
TSTART
...
TCOMMIT
}
ClassMethod SaveDetail()
{
TSTART
...
TCOMMIT
}
正例:
ClassMethod Save()
{
ts
s ret=..SaveMain()
i ret<0 tro q
...
s ret=..SaveDetail()
i ret<0 tro q
...
tc
}
ClassMethod SaveMain()
{
...
}
ClassMethod SaveDetail()
{
...
}
陷阱
- 严格禁止陷阱内部报错导致死进程。
- 陷阱名称统一为
Err+方法名
,除公共陷阱DHCSTERROR.mac
外,其他陷阱都应在对应方法中。
反例:
ClassMethod SaveSomething()
{
s $zt="SaveSomething"
...
SaveSomething
...
}
正例:
ClassMethod SaveSomething()
{
s $zt="ErrSaveSomething"
...
ErrSaveSomething
...
}
格式
- 方法大括号一律换行显示。
反例:
SetDispEvent(){
}
正例:
SetDispEvent()
{
}
- 以下符号添加空格,美观代码,
=
、+
、-
、*
、/
、_
、:
左右加空格,,
之后加空格 。
反例:
GetName(hour,number,year)
{
s name=“yaoxin”
s day=hour*number
s sub=$o(^PHA("DATE",day,hour,""))
}
正例:
GetName(hour, number, year)
{
s name = “yaoxin”
s day = hour * number
s sub = $o(^PHA("DATE", day, hour, ""))
}
- 方法内命令行均采用一个制表符tab缩进,宽度为四个空格宽度。注意是一个
tab
键,而不是按四次空格,可在studio设置(默认为4)
反例:
GetName(hour,number)
{
s name=“yaoxin”
s day=hour*number
s sub=$o(^PHA("DATE",day,hour,""))
}
正例:
GetName(hour, number)
{
s name = “yaoxin”
s day = hour * number
s sub = $o(^PHA("DATE", day, hour, ""))
}
SQL
语句一行5个字段。并且换行后3个tab键为准。逗号在每行行末,不要带入下行开始。因为一行字符书不超过120个,即一屏。
反例:
ClassMethod InsBox(str As %String) As %Library.String
{
&SQL(Insert Into DHC_PHBox (
PHB_No, PHB_Num, PHB_Status, PHB_FLoc_Dr,PHB_TLoc_Dr,PHB_UserCreate_Dr,PHB_DateCreate, PHB_TimeCreate, PHB_PrintFlag, PHB_Remark)
values(
:boxNo, 1, :status, :fromLocID, :toLocID,:userID, :date, :time, "Y", :remark))
q SQLCODE
}
正例:
ClassMethod InsBox(str As %String) As %Library.String
{
&SQL(Insert Into DHC_PHBox (
PHB_No, PHB_Num, PHB_Status, PHB_FLoc_Dr, PHB_TLoc_Dr,
PHB_UserCreate_Dr, PHB_DateCreate, PHB_TimeCreate, PHB_PrintFlag, PHB_Remark)
values(
:boxNo, 1, :status, :fromLocID, :toLocID,
:userID, :date, :time, "Y", :remark))
q SQLCODE
}
- 单行字符串拼写最多5个字段。因为一行字符书不超过120个,即一屏。
反例:
ClassMethod GetString(str As %String) As %Library.String
{
s str = first _ second _third _ fourth _ fifth _six
}
正例:
ClassMethod InsBox(str As %String) As %Library.String
{
s str = first _ second _third _ fourth _ fifth
s str = str _ six
}
- 禁止用同一变量后加数字累加。
反例:
ClassMethod GetString(str As %String) As %Library.String
{
s str1 = first _ second _ third _ fourth _ fifth
s str2 = six
s str = str1 _ str2
}
正例:
ClassMethod InsBox(str As %String) As %Library.String
{
s str = first _ second _ third _ fourth _ fifth
s str = str _ six
}
- 获取多返回值用数组
%ArrayOfDataTypes
。
反例:
ClassMethod GetPatLocDesc(prescNo)
{
s str = wardID _ wardLocDR _ patLocDesc
q str
}
正例:
ClassMethod GetPatLocDesc(prescNo)
{
s array=##class(%ArrayOfDataTypes).%New()
d array.SetAt(wardID,"wardID")
d array.SetAt(wardLocDR,"wardLocDR")
d array.SetAt(patLocDesc,"patLocDesc")
q array
}
- 禁止系统命名混搭方法中出现
s
和set
统一用命名缩写方式。
反例:
ClassMethod GetPatLocDesc(prescNo)
{
s str = “wardID”
set patLocDesc = “病区”
do ..GetName()
q str
}
正例:
ClassMethod GetPatLocDesc(prescNo)
{
s str = “wardID”
s patLocDesc = “病区”
d ..GetName()
q str
}
- 禁止命令出现大小写,统一小写。
反例:
ClassMethod GetName(userID)
{
s name=“yaoxin”
S age=30
}
正例:
ClassMethod GetName(userID)
{
s name = “yaoxin”
s age = 30
}
- 尽量使用对仗词。
add/remove
open/close
get/set
start/end
insert/delete
show/hide
lock/unlock
first/last
next/previous
old/new
- 禁止
{}
和.
同时出现,推荐用使用块级语法,抛弃使用点语法。
反例:
ClassMethod GetName(userID)
{
i flag="yx" d
.i other = "other"{
s name = “other”
}
.s name = "yx"
}
正例:
ClassMethod GetName(userID)
{
i flag="yx" {
i other = "other" {
s name = “other”
}
s name = "yx"
}
}
- 如果
if
语句只有一行,建议使用三元运算符。所有if
语句都要换行写加d
写,即使只有一行
反例:
i name="yx" s age=30
e s age=0
正例:1
i name = "yx" d
.s age = 30
e d
.s age =0
正例:2
s age = $s(name = "yx" : age = "30", 1 : "")
if
嵌套不宜过多,建议不超过3层。
反例:
i name = "yx" d
.s state = 30
.i gender = "男" d
..s state = 20
..i age = "年轻人"
...s state = 10
e d
.s state =0
正例:用策略模式或状态模式封装。
- 多级
if else
考虑用@case
替换。
反例:
i day =1 d
.s desc = "Monday"
e i day =2 d
.s desc = "Tuesday"
e i day =3 d
.s desc = "Wednesday"
正例:
$CASE(day,
1:"Monday",
2:"Tuesday",
3:"Wednesday",
4:"Thursday",
5:"Friday",
6:"Saturday",
7:"Sunday",
:"entry error"
)
- 与或逻辑运算统一使用
&&
、||
,禁止使用其他&
、!
、,
。
反例:
s firstName = "Yao"
s lastNmae = "Xin"
i firstName = "Yao",lastNmae = "Xin" d
.w "true",!
e d
.w "false",!
正例:
s firstName = "Yao"
s lastNmae = "Xin"
i (firstName = "Yao")&&(lastNmae = "Xin") d
.w "true",!
e d
.w "false",!
空行
- 方法与方法之间进行空行隔断。(1个空行)
反例:
Method GetName()
{
...
}
Method GetAge()
{
...
}
正例:
Method GetName()
{
...
}
Method GetAge()
{
...
}
- 空行用来分割功能相似,逻辑内容,意思相近的代码片段,使程序布局更加清晰。
反例:
ClassMethod Execute(params)
{
s $zt="ErrExecute"
s prescNo = $p(params, ..#Del, 1)
s exeCode = $p(params, ..#Del, 2)
s userID = $p(params, ..#Del, 3)
s locID = $p(params, ..#Del, 4)
TSTART
s mExecute = ##class(PHA.DEC.MOB.Execute).%New(prescNo, exeCode, userID, locID)
s ret = mExecute.Execute()
i ret'=0 TROLLBACK
q:ret'=0 ..RetFail(ret)
TCOMMIT
s rows = ..GetPrescDetail(prescNo)
s objectJson = ..GetPrescData(prescNo)
s objectJson.rows = rows
q ..RetObject(objectJson)
ErrExecute
q ..RetFail($ze)
}
正例:
ClassMethod Execute(params)
{
s $zt="ErrExecute"
s prescNo = $p(params, ..#Del, 1)
s exeCode = $p(params, ..#Del, 2)
s userID = $p(params, ..#Del, 3)
s locID = $p(params, ..#Del, 4)
TSTART
s mExecute = ##class(PHA.DEC.MOB.Execute).%New(prescNo, exeCode, userID, locID)
s ret = mExecute.Execute()
i ret'=0 TROLLBACK
q:ret'=0 ..RetFail(ret)
TCOMMIT
s rows = ..GetPrescDetail(prescNo)
s objectJson = ..GetPrescData(prescNo)
s objectJson.rows = rows
q ..RetObject(objectJson)
ErrExecute
q ..RetFail($ze)
}
- 基于第2点,空行之前添加行注释也要空行,并且行注释
/* 规则 */
。
注意:*
号后有一个空格。
反例:
ClassMethod Execute(params)
{
s $zt="ErrExecute"
s prescNo = $p(params, ..#Del, 1)
s exeCode = $p(params, ..#Del, 2)
s userID = $p(params, ..#Del, 3)
s locID = $p(params, ..#Del, 4)
TSTART
s mExecute = ##class(PHA.DEC.MOB.Execute).%New(prescNo, exeCode, userID, locID)
s ret = mExecute.Execute()
i ret'=0 TROLLBACK
q:ret'=0 ..RetFail(ret)
TCOMMIT
s rows = ..GetPrescDetail(prescNo)
s objectJson = ..GetPrescData(prescNo)
s objectJson.rows = rows
q ..RetObject(objectJson)
ErrExecute
q ..RetFail($ze)
}
正例:
ClassMethod Execute(params)
{
s $zt="ErrExecute"
/* 获取入参 */
s prescNo = $p(params, ..#Del, 1)
s exeCode = $p(params, ..#Del, 2)
s userID = $p(params, ..#Del, 3)
s locID = $p(params, ..#Del, 4)
/* 执行方法 */
TSTART
s mExecute = ##class(PHA.DEC.MOB.Execute).%New(prescNo, exeCode, userID, locID)
s ret = mExecute.Execute()
i ret'=0 TROLLBACK
q:ret'=0 ..RetFail(ret)
TCOMMIT
/* 获取json */
s rows = ..GetPrescDetail(prescNo)
s objectJson = ..GetPrescData(prescNo)
s objectJson.rows = rows
/* 返回json */
q ..RetObject(objectJson)
ErrExecute
q ..RetFail($ze)
}
- 事务首尾先后一定要加空行或注释,代表强调。
反例:
Method SaveSomething(params)
{
s ret
ts
...//to do
tc
q ret
}
正例:
Method GetName()
{
s ret
ts
...//to do
tc
q ret
}
注释
- 句首注释用
/* */
,句尾注释用//
,头注释用///
,注意各类注释后应跟空格
反例:
// desc: 获取名称
///Input: 用户ID
ClassMethod GetName(userID)
{
//获取参数
s userID = $p(params, "#", 1) ;用户ID
}
正例:
/// Description: 获取名称
ClassMethod GetName(params)
{
/* 获取参数 */
s userID = $p(params, "#", 1) // 用户ID
}
- 避免无意义注释,尽量用规范的代码命名语言去描述。不要浪费大量时间在毫无意义的注释上。简明扼要,不要啰嗦,注释应当画龙点睛。
反例:
/// Description: 获取名称
/// Input: 用户ID
ClassMethod GetName(userID)
{
}
正例:无须注释
ClassMethod GetName(userID)
{
}
- 所有类加上创建者和日期,创建者应为姓名的全拼,避免出现yx等简写或其他英文名,并简易说明类用途。
反例:
Class PHA.DEC.MOB.API Extends PHA.DEC.MOB.Business
正例:
/// Description: 煎药室接口
/// Creator: yaoxin
/// CreateDate: 2020-03-11
Class PHA.DEC.MOB.API Extends PHA.DEC.MOB.Business
- 避免错误注释误导。可能由于复制过来方法,没有改注释。这样的注释后期开发人员困惑性极大。
反例:
/// Description: 获取年龄
/// Input: 科室ID
ClassMethod GetName(userID)
{
}
正例:
ClassMethod GetName(userID)
{
}
- 方法的完整注释,关于接口中的方法以及存储数据核心方法(如门诊发药),应给与完整注释以及修改记录等。
/// Description: 住院是否存在未退药,提前退费已退
/// Creator: xingming
/// CreateDate: 2019-04-03
/// Table: 涉及的表,普通查询可不写,视方法核心等级
/// Input: DspId(打包表Id)
/// Output: 输出说明
/// Return: 1(已退),0(存在未退申请)
/// Version: V7~V8.3+
/// Caller: 护士站,需关注医嘱调用(转科,出院)
/// Modify: 增加急诊留观判断,2020-02-01,xingming
/// Debug: w ##class(PHA.FACE.OUT.Com).IfIPUnReturn(780)
- 类和方法注释 保持对齐公正。
反例:
/// Description: 住院是否存在未退药,提前退费已退
/// Creator: xingming
/// CreateDate: 2019-04-03
/// Table:涉及的表,普通查询可不写,视方法核心等级
/// Input:DspId(打包表Id)
/// Output: 输出说明
/// Return: 1(已退),0(存在未退申请)
/// Version: V7~V8.3+
/// Caller: 护士站,需关注医嘱调用(转科,出院)
/// Modify: 增加急诊留观判断,2020-02-01,xingming
/// Debug: w ##class(PHA.FACE.OUT.Com).IfIPUnReturn(780)
正例:
/// Description: 住院是否存在未退药,提前退费已退
/// Creator: xingming
/// CreateDate: 2019-04-03
/// Table: 涉及的表,普通查询可不写,视方法核心等级
/// Input: DspId(打包表Id)
/// Output: 输出说明
/// Return: 1(已退),0(存在未退申请)
/// Version: V7~V8.3+
/// Caller: 护士站,需关注医嘱调用(转科,出院)
/// Modify: 增加急诊留观判断,2020-02-01,xingming
/// Debug: w ##class(PHA.FACE.OUT.Com).IfIPUnReturn(780)
其他说明
- 已发布或调试完的程序中不应该再出现断点
b
,调试后及时清除。 - 禁止在涉及大量数据统计的程序中,使用不包含
TMP
的Global
。 - 常用变量参考《变量字典》禁止其他以外命名方式命名。
- 产品组命名规范参考《产品命名及路径.V1》。