ABAP程序开发规范
ABAP报表程序开发规范
一、 目的
为保证在R/3系统中使用ABAP语言开发报表程序的规范性,特制定本开发规范。在本开发规范的约束下,将源代码与报表开发人的相关性降到最低;即只要具备基本的ABAP开发技巧,遵循本开发规范,不同的开发人员开发的同样逻辑的源代码应该是基本相同的。
二、 适用范围
本技术规范适用于捷顺R/3系统的所有开发人员和除标准对象外的所有ABAP报表程序开发。
三、 职责
ABAP开发小组负责程序的开发、传输请求的创建及提交。
BASIS小组负责传输请求向PRD系统的传输。
四、 开发流程
1、 开发人员接收业务顾问提交的开发需求;如果需要,开发人员应当配合业务顾问进行用户需求分析;
2、 开发人员根据开发需求在DEV100中进行程序开发;
3、 开发人员将程序传输至质量保证系统中进行初步测试,测试完毕后通知业务顾问进入用户测试阶段;
4、 程序在质量保证系统中经用户测试通过后,开发人员申请将程序传输至生产系统,相关主管审批通过后,BASIS人员负责将传输请求传输至生产系统。
5、 如果程序需要作为后台程序运行,需要在传输申请中做出说明,由BASIS人员在生产系统中定义后台作业。
6、 开发和修改程序都需要填写开发文档。开发文档存放于服务器的专用目录中,每个程序一个文档,新程序需要新建文档,修改程序需要修改原来的程序文档(在原文档基础上追加内容,不允许删除原文档内容),记录本次修改的内容和请求号等信息。开发程序申请传输生产系统中时,同时提交开发文档审核,相关主管需要同时检查程序和文档的规范性。
五、 命名规则
1、 用户开发对象的命名规则
1) 用户开发对象的名称必须以Z开头,只能使用字母、数字和下划线。用户开发对象包括开发类、程序、函数组、函数、透明表、结构等。
2) 开发类一般使用ZREPORT,如有特殊需要,可以创建新的开发类。
3) 报表程序命名规则:Z<XX>_<Y>_<NN>[ADDITIVE]。
其中,XX为模块名称,现在常用的有以下几种: MM——MM模块,PP——PP模块,SD——SD模块,CS——CS模块,FI——FI模块,CO——CO模块,BC――公共模块,CA――交叉应用;
Y表示程序的类型,目前有四种:R——报表程序,E——批输入程序,S――SmartForm程序,I——接口程序。
NN为序列号,表示该程序在同一模块同类型程序中的编号。比如ZSD_R_01,表示SD模块的一个报表程序。如果业务顾问已经提供需求的编号,则取业务顾问提供的需求编号。
ADDITIVE,程序的附加说明,如项目名称等,可以灵活使用,不是必须的部分。如果创建与程序相关的Include程序,则Include程序的命名中的ZXX_Y_NN部分与主程序相同,通过ADDITIVE部分区分不同的Include程序,如ZXX_Y_NNTOP,ZXX_Y_NNUI等。
特别说明:
如果需要替换原程序,建议将原程序拷贝为ZXX_Y_NNOLD,而新编写的程序的命名与被替换程序的命名一致,不要将新程序命名为ZXX_Y_NNN或ZXX_Y_NNNEW。这样可以避免需要修改需求文档编号与程序编号的对应关系,也避免在日后维护中由于对应关系没有更新而导致错误的修改已废除的程序。
4) 数据字典对象的命名规则:Z<XX>_<Y>_<NAME>
其中,XX为模块名称,现在常用的有以下几种:MM——MM模块,PP——PP模块,SD——SD模块,CS——CS模块,FI——FI模块,CO——CO模块,BC――公共模块,CA――交叉应用;
Y代表对象类型,现在常用的有如下几种: T――透明表, V――视图,S――结构类,I――内表类型;
NAME为对象的名称。尽量给数据字典对象有意义的名称,不要使用序号;如果定义是配置表及其维护视图,可以使用3位的序号。
5) 函数组命名方式:Z_<NAME>
其中,NAME表示函数组有意义的名称,如项目名称,命名应能表示所包含的函数的用途等。
6) 函数命名方式:Z_<NAME>
函数必须指定所属的函数组,NAME表示对函数的说明,使用下划线分隔单词,如Z_ORDER_MODIFY_ABTNR,表示修改订单的部门(ABTNR)字段。
7) 事务代码的命名方式:Z<XX><Y><NN>
即对于报表程序取主程序命名,但将下划线去掉。如果业务顾问已经给出事务代码的命名,则按照业务顾问的命名,只需确保命名以Z开始。
8) SmartForm的命名方式:Z<XX>S<NAME>
其中,XX为模块名称,现在常用的有以下几种:模块名称:MM——MM模块,PP——PP模块,SD——SD模块,CS——CS模块,FI——FI模块,CO——CO模块,BC――公共模块,CA――交叉应用;
NAME为对象的名称。尽量给SmartForm有意义的名称,不要使用序号。
2、 SELECT-OPTION的命名方式:SO_<NAME>
其中,NAME赋予变量有意义的名称,对于类型参照数据字典中表字段的SELECT-OPTION,名称尽量参照该字段的名称。
3、 PARAMETER的命名方式:PA_<NAME>
其中,NAME赋予变量有意义的名称,对于类型参照数据字典中表字段的SELECT-OPTION,名称尽量参照该字段的名称。
4、 程序全局变量的命名方式:G<qualification>_<NAME>
其中,全局变量的命名以G开头,但SELECT-OPTION、PARAMETER及TABLE例外;
qualification主要表示变量的类型,常用的有以下几种:S――结构,T――内表,X――标志变量(变量值为SPACE或‘X’),C――字符(串),N――数值型字符串,D――日期型,I――整型,P――实数;对于类型参照数据字典中表字段的变量,可以省略此部分;
NAME则赋予变量有意义的名称,对于类型参照数据字典中表字段的变量,名称尽量参照该字段的名称。
5、 子程序接口参数的命名方式:P<qualification>_<NAME>
其中,子程序接口参数的命名以P开头;
qualification主要表示参数的类型,常用的有以下几种:S――结构,T――内表,X――标志变量(变量值为SPACE或‘X’),C――字符(串),N――数值型字符串,D――日期型,I――整型,P――实数;对于类型参照数据字典中表字段的参数,可以省略此部分;
NAME则赋予参数有意义的名称,对于类型参照数据字典中表字段的参数,名称尽量参照该字段的名称。
6、 局部变量的命名方式:L<qualification>_<NAME>
其中,子程序中局部变量的命名以L开头;
qualification主要表示变量的类型,常用的有以下几种:S――结构,T――内表,X――标志变量(变量值为SPACE或‘X’),C――字符(串),N――数值型字符串,D――日期型,I――整型,P――实数;对于类型参照数据字典中表字段的变量,可以省略此部分;
NAME则赋予变量有意义的名称,对于类型参照数据字典中表字段的变量,名称尽量参照该字段的名称。
六、 程序注释
程序必须层次清楚,添加详细注释。基本原则是在《ABAP报表详细设计文档》主程序和子程序逻辑中每一段描述性的信息,都应该添加在源代码中相应的位置,并且保证标号的顺序和层次的一致性。
1、 严格按照下列示例填写程序抬头注释信息
*&———————————————————————*
*程序名称:<程序名称> *
*程序目的:<程序功能描述> *
*需求编号:<对应的开发需求编号> *
*作 者:<程序的开发用户名> *
*创建日期:<创建程序的日期> *
*&———————————————————————*
2、 对于子程序,应当在子程序前添加如下注释:
*&———————————————————————*
*& FORM <子程序名称>
*&———————————————————————*
* <子程序的功能说明及逻辑的简述>
*———————————————————————-*
* –> <输入参数名称> <输入参数的说明>
* <– <输出参数名称> <输出参数的说明>
*———————————————————————-*
FORM <子程序名称> [接口定义].
ENDFORM.
3、 对于程序中的全局变量(包括PARAMETER及SELECT-OPTION)及子程序中重要的局部变量应该对其含义、用途做出说明;在声明内表数据类型或内表变量(包括全局变量及局部变量)时,内表的每个字段必须对其进行注解;参考如下示例
eg.1
****供应商信息内表:用于外部输出
DATA:BEGIN OF GT_LFA1 OCCURS 0,
LIFNR LIKE LFA1-LIFNR, “供应商编码
SORTL LIKE LFA1-SORTL, “排序字段
NAME1 LIKE LFA1-NAME1, “名称 1
KTOKK LIKE LFA1-KTOKK, “供应商帐户组
DATLT LIKE LFA1-DATLT, “数据通讯线的号码
END OF GT_LFA1.
eg.2
****复选框, 标志是否前台输出
PARAMETERS:PA_XUI AS CHECKBOX. “复选框, 标志是否前台输出
4、 对数据库查询、子程序/函数/组件的调用、逻辑运算、逻辑处理等程序处理逻辑要有相应注解;对于用于控制语句与WHERE子句里的判断值(常量),要有注解或者说明。
eg.1
****选出BOM表头:指定工厂,指定物料,BOM用途为2或8,替代组为01
SELECT MATNR STLNR WERKS CSLTY
FROM MAST
INTO TABLE ZHEAD
WHERE ( WERKS IN IWERKS OR WERKS IN IWERKS1 )
AND ( MATNR IN IMATNR OR MATNR IN IMATNR1 )
AND ( STLAN = \’8\’ OR STLAN = \’2\’ ) ”类型值为主机或者虚拟BOM
AND STLAL = \’01\’.
eg.2
****判断用途选择,前台或后台输出
IF SOPT EQ \’X\’. “输出到前台文件
PERFORM EXPORT_DATA_FT. “将数据导出到客户端文件
ELSE. “输出到应用服务器文件
PERFORM EXPORT_DATA_BG. “将数据导出到应用服务器文件
ENDIF.
5、 当修改程序时,在程序抬头注释后附加程序修改注释:
*&———————————————————————*
*修 改 人:<修改程序的开发用户名> *
*修改日期:<修改程序的日期> *
*修改说明:<本次修改的逻辑处理和必要的说明信息> *
*&———————————————————————*
在修改其他开发人员的程序时不要在原代码行上进行修改,也不要直接删除原代码行;应该将要修改的代码行标注为注释行,并按如下例子条件注释,如果:
1) 对原代码行进行修改,
*———————————————————————-*
*BEGIN MODIFY BY <用户> <修改日期>
*<修改原因>
*<原代码行>
<新代码行>
*END MODIFY BY <用户>
*———————————————————————-*
2) 删除整段原代码,
*———————————————————————-*
*BEGIN DELETE BY <用户> <修改日期>
*<删除原因>
*<原代码行>
*END DELETE BY <用户>
*———————————————————————-*
3) 新增代码行,
*———————————————————————-*
*BEGIN INSERT BY <用户> <修改日期>
*<新增原因>
<新代码行>
*END INSERT BY <用户>
*———————————————————————-*
七、 数据库访问与内表的使用
1、 没有相关授权,禁止对SAP系统提供的透明表使用INSERT(插入)、UPDATE(更新)、DELETE(删除)等可以变更底层数据库信息的语句;
2、 对一些数据量比较大的透明表查询,尽可能在查询条件中使用主键和索引,如果有多个主键或索引字段,尽可能全部使用,如果不能全部使用,尽可能使用按从左至右的次序使用主键或索引字段。
例如:表BKPF的主键包含3个字段,BUKRS,GJAHR,BELNR,最好3个主键字段共同使用,如果不能全部使用,则至少包含BUKRS;如果使用GJAHR和BELNR,或者使用BELNR,而不指定BUKRS,都会造成效率的下降。
3、 如果访问的是簇表,必须使用主键,如果不能使用,可以先查询这个簇表的索引表,再根据索引表的记录访问该簇表。注意,簇表不能用于多表连接查询。
例如:需要查询表BSEG,如果不能使用主键,则需要先查询表BSID和BSAD,然后根据得到的主键查询表BSEG。
4、 对透明表查询,只选择需要的字段,禁止使用如下语句:
SELECT * FROM TABLE1.
应该使用以尽量减少需要传递的数据量:
SELECT FIELD1 FIELD2 … FROM TABLE1.
5、 如果只读取透明表的一条记录,使用SELECT SINGLE。
6、 根据内表的内容查询透明表,禁止使用下面的语句:
LOOP AT ITAB.
SELECT FROM TABLE1 WHERE FIELD1 = ITAB-FIELD1.
…
ENDLOOP.
应该使用下面的语句:
DESCRIBE TABLE ITAB LINES LINCT.
IF LINCT EQ 0.
STOP.
ENDIF.
SORT ITAB BY FIELD1.
DELETE ADJACENT DUPLICATES FORM ITAB.
SELECT FROM TABLE1
FOR ALL ENTRIES IN ITAB
WHERE FIELD1 = ITAB-FIELD1.
这样可以减少读取数据库的次数,因为FOR ALL ENTRIES会自动遍历内表,并且将WHERE条件以OR关键字连接(系统默认5个OR连接)。使用FOR ALL ENTRIES IN ITAB要注意,ITAB不能为空,否则会造成该WHERE条件无效,同时还需要对ITAB按照字段FIELD1进行排序,并且删除表中的重复记录,同样是为了减少访问数据库的次数。
但当可以使用表连接查询时尽量不要使用FOR ALL ENTRIES,因为FOR ALL ENTRIES往往会形成多条SQL语句,导致数据库访问次数的增加。
7、 不要使用透明表的嵌套
SELECT FROM TABLE1.
SELECT FROM TABLE2.
…
ENDSELECT.
ENDSELECT.
8、 建议少使用INNER JOIN或者OUTER JOIN,因为这些语句不会访问DATA BUFFER,会造成效率的降低。可以创建一个VIEW,实现多个透明表的关联。INNER JOIN超过三个表,或者是两个数据量超过10000条记录的透明表做INNER JOIN且有着关键字关联关系(例如凭证抬头和凭证行项目),必须定义视图的方式实现。
9、 查询透明表时,不要使用ORDER BY,即使是主键,也要慎用。因为很容易造成全表搜索。将索引操作应用到内表上。
SELECT FROM TABLE1
WHERE
ORDER BY FEILD1.
10、 检索内部表时,避免使用下面的语句:
LOOP AT ITAB.
IF ITAB-FIELD1 = VARIANT1.
…
ENDIF.
ENDLOOP.
应该使用下面的语句:
LOOP AT ITAB WHERE FIELD1 = VARIANT1.
…
ENDLOOP.
对于数据量较大的Standard 内表,使用下面的语句可以提高检索效率:
SORT ITAB BY FIELD1.
LOOP AT ITAB WHERE FIELD1 = VARIANT1 BINARY SEARCH.
…
ENDLOOP.
如果内表仅用于检索数据,没有增删改等操作,而且检索的字段不会发生变化,可以将内表定义为Hashed内表,其主键定义包含检索时使用的字段。
11、 从透明表读取数据到内部表时,不要使用下面的语句:
SELECT FROM TABLE1.
ITAB-FIELD1 = TABLE1-FIELD1.
APPEND ITAB.
ENDSELECT.
应该使用下面的语句:
SELECT FROM TABLE1 INTO TABLE ITAB.
12、 原则上不要使用LOOP多层嵌套
LOOP AT ITAB1.
LOOP AT ITAB2.
…
ENDLOOP.
ENDLOOP.
应该使用下面的语句:
LOOP AT ITAB1.
READ TABLE ITAB2 WITH KEY FIELD1 = ITAB1-FIELD1.
IF SY-SUBRC = 0.
…
ENDIF.
ENDLOOP.
13、 完成报表程序的开发后,要通过事务代码ST05对程序的执行进行SQL跟踪,检查程序对数据库的访问情况,避免出现两种情况:单条语句执行超过2000毫秒,或者单条语句反复执行超过10次,这些语句都是需要优化的。单条语句执行时间过长,检查语句是否使用了索引,要避免全表搜索。单条语句执行次数过多,检查程序逻辑,是否可以减少访问数据库的次数。
14、 在一个LOOP中,工作区在当前循环的最后一次操作后,下次循环开始之前,在循环的最后一句程序语句中,应该用CLEAR清空。对于非循环的情况,一旦这个工作区中的值不再被处理,应该用CLEAR清空。
例:LOOP AT……
……
CLEAR WA.
ENDLOOP.
X = WA.
CLEAR WA.
15、 当程序不再使用内表中的数据时,可以使用REFRESH语句清空内表中的数据;如果内表在程序中不再继续使用,而且内表中保存了大量的数据,应该使用FREE语句清空内表中数据并释放分配的内存。
八、 结构化和模块化
结构化和模块化遵循如下几个原则:
a) 如果程序的逻辑部分的编码量(数据声明不包括在内)超过100行,必须进行结构化和模块化(编写功能相对独立的子程序和FUNCTION);
b) 对于被其他程序共享的源代码,要将其包装在FUNCTION内,提高源代码的重用性;
c) 程序全局类型定义与变量的声明及SELECTION-SCREEN的定义,做为单独的INCLUDE文件,供程序引用。例:INCLUDE ZFI_R_01TOP
d) 如果系统提供了同样功能的FUNCTION,使用系统提供的FUNCTION。
对于主程序,应按照下面示例进行过程化和结构化。
*&———————————————————————*
*& SELECT-OPTIONS
*&———————————————————————*
SELECT-OPTIONS:
SO_VKORG FOR VBAK-VKORG OBLIGATORY
MEMORY ID VKO,”Sales organization
SO_VTWEG FOR VBAK-VTWEG, “Dis.channel
SO_VKBUR FOR VBAK-VKBUR, “Sales office
SO_KUNNR FOR VBAK-KUNNR, “SOLD-TO
SO_ERDAT FOR VBAK-ERDAT, “Order creation date
SO_AUART FOR VBAK-AUART DEFAULT \’ZTOR\’ , “Order type
SO_VBELN FOR VBAK-VBELN, “s/o no,
SO_ERNAM FOR VBAK-ERNAM DEFAULT SY-UNAME,
“Name of Person who Created the O
SO_GBSTA FOR VBUP-GBSTA.
*&———————————————————————*
*& INITIALIZATION
*&———————————————————————*
INITIALIZATION.
P_ERDAT-LOW = SY-DATUM.
P_ERDAT-LOW+6(2) = 01.
P_ERDAT-HIGH = SY-DATUM.
APPEND P_ERDAT.
*&———————————————————————*
*& TOP-OF-PAGE
*&———————————————————————*
TOP-OF-PAGE.
PERFORM WRITE_HEADER.
*&———————————————————————*
*& AT LINE-SELECTION
*&———————————————————————*
AT LINE-SELECTION.
GET CURSOR FIELD F VALUE V.
CHECK NOT ( V IS INITIAL ).
PERFORM CALL_TRANSACTION.
PERFORM CHECK_PERIOD.
PERFORM GET_BILLING_DATA.
PERFORM ANALYSIS_DATA.
PERFORM SORT_CHANGING USING OK_CODE_M.
PERFORM PRINT_RTN USING OK_CODE_M.
*&———————————————————————*
* START-OF-SELECTION.
*&———————————————————————*
START-OF-SELECTION.
SET PF-STATUS \’ZOR3\’.
PERFORM GET_DATA.
九、ABAP报表详细设计文档编写的原则
要求在详细设计文档中体现每一段不可分割的子逻辑,而在编码阶段,直接将这些子逻辑的伪代码作为注解体现在源代码中。
4、修改补充:
按版本依次填写每次修改内容:
1)版本信息记录:程序修改必填,记录本次修改对应文件管理中的版本信息;
2)需求描述:程序修改必填,记录本次修改的业务驱动或系统驱动原因;
3)修改内容描述:程序修改必填,记录本次修改的逻辑处理和必要的说明信息;