前言
随着工作的时长,看到的代码和写的代码也越多。久而久之,就会发现自己或者其他人写的代码不够整洁,甚至是冗余,可能也在某个时刻吐槽过:“XXX 写的什么如 shi 一般的代码”。
刚好对代码整洁之道有所耳闻,这不就通过搜索找到了 Clean ABAP。
这份 ABAP 代码整洁之道指南针对 ABAP 改编自 Robert C. Martin 所著的 Clean Code。中文翻译版:《代码整洁之道》。
-
Clean ABAP Cheat Sheet 总结了 Clean ABAP 的准则,并以简短的格式进行了优化,便于打印。
-
黄金准则:在一页纸上总结了最重要的准则。
如图:
这指南里的所有内容我就不一一介绍了,就简单针对打印版和工作中实际需要来快速浏览一下都有哪些整洁代码需要的规则吧。
命名
使用描述性名称
例如 max_wait_time_in_seconds,不要使用 iso3166tab
不要只把注意力放在数据类型和技术编码上。它们对理解代码几乎没什么贡献。
DATA iso3166tab TYPE STANDARD TABLE ...
METHODS read_t005 ...
倾向于解决方法和问题描述的术语
- 业务层:
account,ledger - 技术层:
queue,tree
使用复数
使用 countries 而不是 country
使用可读的名称
使用 detection_object,而不是 dobj
避免缩写
使用 customizing,而不是 cust
任何地方使用相同的缩写
dobjt , dot, dotype
人们会搜索关键字来查找相关代码。为此,应对相同事物使用相同缩写。例如,始终将 "detection object type" 缩写为 "dobjt",而不是混合使用 "dot"、"dotype"、"detobjtype" 等等。
类使用名词,而方法使用动词
类:account、person、address
方法: withdraw,is_empty
避免噪音词
主要指与系统容易发生歧义的词:data,controller,object
为相同概念选一个词命名
“查询/遍历/检索”功能的词汇:read,retrieve, query
当我们使用设计模式时,才使用设计模式的名称
factoryfaçadecomositedecorator
避免编码,尤其是匈牙利符号和前缀
使用:
result = a + b
而不是:rv_result = iv_a + iv_b
命名法则总结
以上就是命名方法中的整洁之道,但是在实际开发过程中,有时候会结合 SAP 已经定义好的字段进行命名,而这些命名之法已经是根据德语或者英语写好了,比如银行信息记录表 bnka 中:
bank_key被命名为banklbank_country被命名为banksbank_name被命名为banka
所以个人在做报表时,会为了方便使用 INTO CORRESPONDING FIELDS OF TABLE 语法,因此会直接将变量命名为 SAP 定义好的字段,不然还需要代码挨个去对应。
但在做接口时,会选择命名为与对应 bapi 结构命名相同的名称:
语言
顾及传统
在运用新语法之前先看是否符合版本:
比如 Select 语句:
# 7.40 前:
DATA itab TYPE TABLE OF dbtab.
SELECT * FROM dbtab INTO TABLE itab WHERE field = lv_field.
# 7.40 后:
SELECT * FROM dbtab INTO TABLE @DATA(itab) WHERE field = @lv_field.
比如查询记录是否存在的语句:
# 740 前:
READ TABLE itab ...
TRANSPORTING NO FIELDS.
IF sy-subrc = 0.
...
ENDIF.
# 740 后:
IF line_exists( itab[ ... ] ).
...
ENDIF.
注重性能
测量可能较慢的模式:意思就是不要一开始就追求高性能代码而花费大量的时间,可以先通过保证代码的整洁性的前提下完成功能,然后通过系统效率分析工具来找出可能需要优化的代码段。
面向对象编程优于过程式编程
对类的使用优于函数(functions)和报表程序(report)
面向对象的程序(类、接口)比过程式代码(函数、程序)分段更清晰,并且可以更加容易地进行重构和测试。尽管在某些情况下必须提供过程式对象(对 RFC 用函数、对事务用程序),但这些对象除了调用提供实际功能的相应类之外,不应该再干别的:
FUNCTION check_business_partner [...].
DATA(validator) = NEW /clean/biz_partner_validator( ).
result = validator->validate( business_partners ).
ENDFUNCTION.
函数式语言结构优于过程式语言结构
使用:
index += 1. # or
index = index + 1.
不要使用:
ADD 1 to index.
使用 DATA(uppercase) = to_upper( lowercase ). 。而不用 TRANSLATE lowercase TO UPPER CASE.
使用 result = VALUE #( FOR row IN input ( row-text ) ). 。而不用:
LOOP AT input INTO DATA(row).
INSERT row-text INTO TABLE result.
ENDLOOP.
避免过时的语言元素
在升级 ABAP 版本时,务必要检查是否有过时的语言元素,避免再使用它们。
比如 MOVE 已过时,已被赋值操作符 = 所取代。具有赋值操作符的语句右侧是通用表达式位置。
使用:
DATA itab TYPE TABLE OF i WITH EMPTY KEY.
...
DATA(lines) = lines( itab ).
不要使用:
DATA itab TYPE TABLE OF i WITH EMPTY KEY.
DATA lines TYPE i.
...
MOVE lines( itab ) TO lines.
明智地使用设计模式
仅在合适且有明显好处的地方使用。不要为了使用而到处用设计模式。
在开发过程中,个人还真的很少使用设计模式。最近部门需要开发一个五级审批结构,我就在思考这里面要怎么利用上所学的设计模式。
注释
在代码中表达意思,而不是在注释中
使用 assert_is_valid( input )
而不是:
" check whether user input is valid"
check( x ).
整洁代码并不是禁止您为代码写注释,而是鼓励您想出更好的替代方法。只有想不出替代方法时才使用注释。
注释绝不是糟糕命名的借口
使用 data totol_sum,而不是:
" the total sum
DATA s
使用方法而非注释来对代码分段
这样不但能够更加清晰地体现代码的意图、结构和依赖关系,同时还能避免在块与块之间因临时变量未清空引起的错误。
do_a()
do_b()
而不是:
" -----------------
" do a
a = b + 1.
" -----------------
" -----------------
" do b
x = a / 10.
" -----------------
这个我就在参考前人的代码中犯了这个错误,在代码中加了很多 “ " -----------------” 的注释,现在看起来非常不简洁...
写注释是要解释为什么这样做而非该代码是什么
" can be missing if...
READ TABLE itab
而不是:
" read the itab
READ TABLE itab
" select alert root from database by key
SELECT * FROM d_alert_root WHERE key = key.
设计应放到设计文档里而不是代码里
" some general observations on this
比如下面一大段解释文本:
用引号 " 而非星号 * 加注释
在 ABAP 中引号 " 和 星号 * 都能用于注释,但是星号需要在行的顶格,所以缩进位置会显得很奇怪:
" inlines nicely
* aligns to weird places
加引号的注释及其注释语句一同缩进:
METHOD do_it.
IF input IS NOT INITIAL.
" delegate pattern
output = calculate_result( input ).
ENDIF.
ENDMETHOD.
加星号的注释往往造成缩进异常:
" anti-pattern
METHOD do_it.
IF input IS NOT INITIAL.
* delegate pattern
output = calculate_result( input ).
ENDIF.
ENDMETHOD.
将注释放在与其相关的语句前面
" right here
do_it(). " not there
" nor there~~
删除无效代码而不是注释它
* READ TABLE
当您发现类似内容时,请将其删除。这里显然不需要代码,因为应用程序顺利运行并且所有测试都通过了。以后可根据版本历史记录再生删除的代码。如果需要永久保留某一段代码,请将其复制到文件或 $TMP 或 HOME 对象中。
在学习的过程中,带我入门的师父让我别删代码,都是注释,然后再遗留代码中就看到一大堆注释的代码,其实反正有版本管理,为何要留着我至今都不太能理解,但是也只能照着做。
使用 FIXME、TODO 和 XXX 并添加自己的标识
METHOD do_something.
" XXX FH delete this method - it does nothing
ENDMETHOD.
FIXME指向内部事件正在形成的过小或过大的错误。TODO是您要在不久之后编写代码的地方。XXX标记出有效但还可以进一步优化的代码。
输入这类注释时,请添加昵称、姓名缩写或用户,这样可方便共同开发者与您联系并可以在不清楚注释的意图时向您询问问题。
勿添加方法签名和注释结尾
" anti-pattern
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method CALIBRATION_KPIS=>CALCULATE_KPI
* +-------------------------------------------------------------------------------------------------+
* | [--->] STRATEGY_ID TYPE STRATEGY_ID
* | [--->] THRESHOLD TYPE STRATEGY_THRESHOLD
* | [--->] DETECTION_OBJECT_SCORE TYPE T_HIT_RESULT
* | [<---] KPI TYPE T_SIMULATED_KPI
* +--------------------------------------------------------------------------------------</SIGNATURE>
几十年前,当在检查代码或处理数十页的打印输出内容时,如果看不到方法签名,这些注释可能会对您大有帮助。但现在,所有 ABAP IDE(SE24、SE80、ADT)都可以轻松显示方法签名,因此这些注释只是干扰而已。
在基于表单的编辑器 SE24/SE80 中,按_签名_按钮。在 ABAP 开发工具中,选中方法名称然后按 F2,或将 _ABAP 元素信息_视图添加到您的透视图中。
同样,注释结尾也是多余的。几十年前,当程序和函数以及内部嵌套的 IF 长度达到数百行代码时,这些注释可能很有用。但如今的编码风格发生了变化,方法非常简短,可以轻松看到 ENDIF 或 ENDMETHOD 属于哪个开头语句:
" anti-pattern
METHOD get_kpi_calc.
IF has_entries = abap_false.
result = 42.
ENDIF. " IF has_entries = abap_false
ENDMETHOD. " get_kpi_calc
勿复制消息文本作为注释
" Business document not found
MESSAGE e100.
ABAP 文档仅适用于公共 API
PRIVATE SECTION.
"! Reads something
METHODS read_something
编写 ABAP 文档来记录公共 API,这意味着这些 API 可供其他团队或应用程序的开发人员使用。不要为内部内容编写 ABAP 文档。
ABAP 文档与所有注释一样都有相同的弱点,也就是说,它很快会过时,然后会变得有误导性。因此,您应该只在有意义的情况下使用,而不要为一切内容强制编写 ABAP 文档。
总结
本文基于 CleanABAP 梳理了 ABAP 代码命名、语言和注释的简洁之道,这些规则在编写可读性代码是非常重要的。
- 命名要简洁清晰、有意义易于理解,避免使用缩写或者无意义的名称,更不应该将注释用于解释毫无意义的变量。
- 语言要符合最新的版本语法规则,尽量使用高效的语法规则,类语法优于函数式和报表程序,避免使用过时的语法。
- 注释要清晰和明确,通过代码解释功能,而不是通过注释解释代码。使用合适的缩进使得注释处于合理的位置。
简而言之,编写整洁的 ABAP 代码可以提高代码的可读性和维护性,使代码更易于理解和维护。希望你能看完本篇文章之后有所收获。