技术支持程序员程序书写规范
编制:李群巍
日期:
BSHIS的软件客户化工作是一个庞大的系统工程。客户化工作的好坏,软件质量的好坏直接影响着工程实施和工程进度。为了保证技术支持部程序员编写程序的质量和技术支持的质量,特制定以下技术规范和代码书写注意事项。
此规范是个初稿,在实际应用中,尚需要不断完善和调整。另外,请各序员在实际操作过程中,提出自己的看法和建设性的意见和建议,以使规范不断完善。
若是比较简单的错误,很容易修改的,请自行修改,并及时将修改资料交到部门领导,到时候统一提交到质量部,以便及时通报各个技术人员。若是牵涉到很复杂的或者是有很大的业务调整,请提交领导审批后再进行修改。
:如:新增系统公用功能,虽然是可以放在以上两个PBL,但为了不致被覆盖,最好还是自己新建PBL的好。以上PBL中的代码也不要去擅自去调整。
DATAWINDOW有修改的话,请在继承的模块中引用新的从原来的复制下来再进行修改过的DATAWINDOW,而不要直接去修改原来的DATAWINDOW。
请参考产品质量部的《程序编制规范.doc》
下面着重讲讲一些经常在工作中出现的不规范的情况和应该注意的地方:
典型的不规范的情况有:
如:局部变量命名为:integer gl_ksdm
实例变量命名为:integer ll_ksdm
我们命名原则的指定,宗旨是看到这个变量就应该知道是什么变量(全局、局部、实例、共享),是什么类型。良好的变量命名习惯可以使程序阅读起来很轻松,也可提高工作效率和错误的理解导致的工作不便。
变量的类型
| 对象 | 类型 | 前缀 | 备注 |
| 整型数字 | Int | I_ | 界面中右对齐 |
| | Long | L_ | 界面中右对齐 |
| 浮点型数字 | Double | D_ | 界面中右对齐 |
| | Decimal | Dc_ | 界面中右对齐 |
| 日期 | Date | D_ | 界面中左对齐或居中 格式一般为: yyyy.mm.dd |
| | Datetime | Dt_ | Yyyy.mm.dd hh:mm:ss |
| | Time | T_ | HH:MM:SS |
| 类实例 | 可视 | Vu_ | |
| | 非可视 | U_ | |
| 字符串 | String | S_ | 界面中左对齐或居中 |
| 结构体 | Struct | Str_ | |
| 布尔型 | Boolean | B_ | 居中 |
变量的范围:
| 前缀 | 含义 |
| G | 全局 |
| S | 共享 |
| I | 实例 |
| L | 局部 |
| A | 参数 |
变量命名
变量范围+变量类型+‘_’+变量名称
例:全局的日期为Gd_today,门诊号参数As_mzhm
注:BSHIS2.2公共全局类名:Uo_support::U_supporclass
BSHIS2.2全局参数结构名:Base_info::Base_info
BSHIS2.2窗口数据传输变量结构:S_Exchange::S_Exchange
一般将窗口相关的DATAWINDOW,具有和窗口相同的前缀。
这样做的好处是:复制模块或者整理和查看程序的时候很容易
如:w_yk_jchz (药库系统的进出汇总模块)
相关的datawindow可命名为 d_yk_jchz
其他相关的模块和DATAWINDOW都命名为包含 _yk_jchz_ 做为前缀的名字
目前存在乱命名的情况,严重的甚至出现同个系统的不同PBL出现名字重复。
有时候程序数据检索错误,就是这个原因导致的,有时候我们还可能花很大的力气去找原因。
如:his2.1系统药房系统中 d_ypxx 就出现过同名异构的DATAWINDOW
GF_XXXX(GF+_+函数名称)
GF_XX_XXXX(GF+_+系统简称+_+函数名称)
WF_XXXX(WF+_+函数名称)
Object.XXXX(函数名称)
Object.of_XXXX(被其他对象和模块调用)
Object.uf_XXXX(内部调用)
GE_XXXX(GE+_+函数名称)
LE_XXXX(LE+_+函数名称)
DD_XXXX
D_XX_XXXX(D+_+系统简写+_+数据窗口名称)
主要,窗口私用的DATAWINDOW的命名的前缀除 d_ 外 一般和 窗口的名字同
如:d_yk_jchz 属于 w_yk_jchz 模块
U_XXXX(非可视类)
VU_XXXX(可视类)
主要是涉及医院基础流程的东西,如不修改,医院的HIS流程将走不通。对此问题,一般根据医院自身的特色和BSHIS的程序特点,双放协商一种比较好的折中的方法。
如:
药库出库处理模块可监控药房是否已确认入库
某个查询模块,要增加几个过滤条件
药库入库、出库单可连续打印
如:
有些医院药库本院自制的药品较多,入库要与一般采购入库分开(区分),若放到其他入库中,则许多采购入库的分析模块不能使用。解决:可新增一个供货单位(如:“本院自制”),采用采购入库模块即可。
5)与其他技术人员及时交流
特别是一些比较难查的错误,可先问问别的技术人员是否已经处理过,避免重复劳动。
6)有些较大的流程调整性的修改,一般需要讨论或者和院方进行协商后再进行修改。
总结出共性的需求和比较普遍的客户化工作,做一些共享模块和公用模块,为下一次需求修改作预备工作。如时间许可,在改程序时应尽量考虑公用性,可以在其他医院或其他系统中比较容易地挂接。
建议每个程序员自己建议一套自己的客户化支持库,可大大提高自己的代码书写速度和质量,并定期与其他程序员进行交流。
如:HIS22的病区药房发药处理对象(基本医嘱、急诊医嘱、医技用药、出院带药等)就是一个例子。
目前在客户化的时候在此方面比较欠缺。
当然,在设计对象时,应尽量考虑通用性和可移植性。不要使对象内部的处理逻辑太依赖外部的模块代码的数据。
典型的面向对象的应用是各地的医保支持处理代码,可充分利用面向对象的编程技术。
对于医院新增加的功能模块所使用的模块,一般单独放在一个PBL中
新增PBL的命名规范为:
<系统简称>_<医院简称>.pbl
<系统简称>采用系统名称的首字母组成。
<医院简称>采用医院名称的首字母组成。
如浙江妇保的药房系统新增了模块,命名为:yf_zjfb.pbl
也可以命名为 yf_expand.pbl
不得以程序员已经的名字命名PBL
不能在新增的PBL中出现重复的对象,以前老的版本不用的PBL,不要放在程序目录下,避免其他工程人员在编译时将其加入到编译路径中。
不要中药库(房)一套程序,不要西药库(房)一套程序,病区药房一套程序,导致不必要的代码冗余和后期代码维护的混乱。
只要药库程序一套,药房程序一套就可以了。若有中西的代码区别,在内部程序做处理。
若操作员使用的门诊系统和财务人员使用的有功能上的不同,也不要搞成几套程序,可用系统参数或者其他方法加以控制。
程序写好了后,还需要注意程序的性能,这个特别是对比较大的医院要求特别的苛刻。
下面是程序在性能方面的一般解决方法和注意事项:
不更新数据时保持 SQLCA.AUTOCOMMIT 为 TRUE,避免当前事务一直处于激活状态,影响别的事务。就是要写 gf_begin_transaction() 和 gf_commit_transaction()来处理事务。
按经常被检索的单元物理排序。
如:ZY_BQYZ表,按SRKS字段进行批量处理的机会比较多,所以在此上建立物理所以可减少锁表,同时可加快检索速度(检索物理索引时比逻辑索引快的多)。因为 Sql Server 需一个一个数据页的访问,建立Clustered 索引可减少切换页面的时耗,若执行更新数据语句,也可减少锁表。
缩短一个事务更新数据的时延,若在事务中有运算,应先在本地全部做好,再用 DataWindow 一次性更新。
如:住院系统中病人性质转换。
Cursor 在执行 Fetch 时始终与服务器保持通信,若在 Fetch 语句中嵌入查询或其他比较耗时的语句,将导致整个查询很慢。替代的办法是:先用 DataWindow 一次性检索数据到本地,在用循环替代 Fetch。
如:住院个人日结、汇总报表优化属于这一类。
如:将 ZY_BQYZ 表中出院病人的医嘱转到 ZY_BQYZ_CY (历史医嘱表)中,可保持 ZY_BQYZ 表规模相对较稳定,保证业务速度。
可象院长查询系统一样,一些历史性且不随时间的推移而改变的数据,对它们进行统计,可先将常用统计方法的结果保存起来,避免每次查询时都需重新统计。
1)在 Where 字句中检索字段上加索引,若为多字段联合检索,可在这些字段上加复合索引。一些表中经常被检索的字段未加索引。
如:MS_THMX 中的 CZGH、JZRQ。
若表中加了复合索引,在书写 Sql 语句时,and 语句中的字段应按复合索引中字段的先后顺序,否则索引会失效。
ZY_BQYZ表中加了在XMLX,YPLX复合索引,检索语句应写型如:
XMLX=1 AND YPLX=0
而不是 YPLX=0 AND XMLX=1
2)避免使用 Sql Server 函数,如 DateDiff(),函数会使索引失效。
例:
原 Sql 语句:
DATEDIFF(DAY, TZSJ, GETDATE())=0
优化的Sql 语句:
// 变量申明
datetime ldt_datebegin, ldt_dateend
ldt_datebegin = datetime(date(gf_server_date()), time(“0:0:
ldt_dateend = datetime(date(gf_server_date()), time(“23:59:
// Sql
TZSJ >= :ldt_datebegin AND TZSJ <= :ldt_dateend
3)少用字符串类型字段,多用数值型字段
要与其他表作连接用的字段,最好用数值型。因为,一般字符型位数相对数值型较长。用数值型字段,可减少 Sql Server 检索比较的时间。
4)尽量少用 OR 子句
OR 子句将导致 Sql Server 用 Nested Loop 的方法检索数据
IN 子句中若为常量,Sql Server 实际上是转化为 OR 语句来实现。
5)IN 子句中应为常量,避免用子查询
如:医嘱项目执行模块,原来的 Sql 语句片段为:
(ZXKS=0 OR ZXKS IS NULL OR ZXKS IN (SELECT KSDM AS ZXKS FROM GY_KSWK WHERE WKDZ=:as_wkdz)
优化为:
(ZXKS=0 OR ZXKS IS NULL OR ZXKS IN (:ala_ksdm))
其中,ALA_KSDM 为数值数组
6)避免用 IS NULL 或 ISNULL(FYDJ*FYSL,0)=0 类似的语句
在表设计时,要有初值(BSHIS2.2已考虑此问题)。ISNULL() 将使索引失效。
如果一定要用,请使用 IS NULL,而不使用 ISNULL() 函数。
7)避免使用子查询,子查询将导致 Sql Server 用 Nested Loop 的方法检索数据。
特别是相关子查询要少用。
无关子查询:
SELECT * FROM ZY_FYMX WHERE ZYH IN (SELECT ZYH FROM ZY_BRRY WHERE CYPB=8)
以上与下面的相同
SELECT ZY_FYMX.* FROM ZY_FYMX, ZY_BRRY WHERE
ZY_BRRY.CYPB=8
相关子查询
SELECT KSDM,
(SELECT TOP 1 WKDZ FROM GY_KSWK WHERE GY_KSWK.KSDM=
GY_KSDM.KSDM) AS WKDZ
FROM GY_KSDM
即一个或多个字段与外部的数据集相关联的子查询,这种查询效率很差
功能进行GROUP BY 的或者先进行汇总的先在SQL语句中去实现,不要到DATAWINDOW中去汇总处理。
典型的败笔:
门诊医生站系统的科室就诊情况统计
请参考《HIS医保接口设计规范(草稿).doc》
最关键的原则:1)将医保业务和HIS业务分割开
2)医保一般以地区为单位,要保证同个地区的医保处理程序一致
PB的DATAWINDOW在设置UPDATE属性时,本来可以按“Primary Key”获得主键的,但是PB经常出现错误,找到的不是表的主键,而是其他字段。这时需要程序员自己设置好主键。(如:his2.2x药房系统的w_fycl的基本医嘱处理DATAWINOW)
下面的界面中,按了“Primary Key”按钮获得主键错误,需要手工设置。务必注意。