共计 4153 个字符,预计需要花费 11 分钟才能阅读完成。
最近有粉丝在后台给我留言,说新知识太多,“学不动了”。所谓温故而知新,今天我们就来重温下 ABAP 里的 Code Inspector 的用法。
2015 年 6 月,我在 SAP 社区上写了一篇博客,介绍了 ABAP Code Inspector 里一些大家不常用的功能,在 2016 年 SAP 社区改版,所有文章阅读量清零之后,到现在仍然有 17000 多的点击量。
https://blogs.sap.com/2015/06…
本文是 Jerry 英文博客翻译成中文的浓缩版,并且假定读者都知道如何使用 SCI 这个事务码。对 ABAP Code Inspector 还不熟悉的朋友,可以查阅我另一篇讲述其用法的博客:
A Small tip to get all transparent tables used in ABAP code
我们可以在 ABAP Code Inspector 的检查变体 (Check Variant) 里,根据自己的需要灵活地选择对 ABAP 代码进行哪种类型的扫描动作。
下图是一个例子,意思是对 ABAP 代码中所有对数据库表产生了读写访问之处,进行 ”Table Names from SELECT Statements” 的扫描。该扫描的具体行为,可以点击蓝底白色的感叹号图片,以获得帮助文档。下图这个例子里勾取的选项,意思是检查被访问的数据库表,在 SE11 的 ABAP 字段里的 Technical Settings 是否正确被维护了,比如表的缓存类型是否设置正确。
Performance Check
Select-Statement can be transformed. X% of fields used – 检查内表字段的使用率
假设我们使用 SELECT * 从一张表里读取数据到 ABAP 内表,然后在后续代码中只使用到了 A 个字段,而读取的表在 SE11 里总共有 B 个字段,那么 A 除以 B 的结果越小,说明读出来的内表字段使用率越低。
也就是说,你或许该考虑只 SELECT 真正需要的字段来替代 SELECT *? 只需要在上图设置里维护一个最低阀值,当 Code Inspector 扫描代码时,一旦检测到使用率低于维护的阀值就会报错。上图的 20 意思是 20%.
Search DB Operations in loops across modularization units
Jerry 2007 年刚加入 SAP 开始学习 ABAP 编程时,前辈们就告诫过我,不要在 LOOP 里使用 SELECT 语句,这样会极大影响代码的性能。
上图是通过 Code Inspector 扫描出来的一个例子,在双重 LOOP 循环里使用 SELECT 读取数据库表 CRMD_DPP_HI_BLCK.
Nested Loops – 嵌套循环的检测
尽管当应用代码里嵌套循环的循环次数不大时,对代码运行的绝对时间没有太大影响——然而编写具有至少指数级时间复杂度的代码,在任何上下文里都不是一个好的编程习惯。
这个设置能够帮助我们快速找到所有的嵌套循环。
Copy current table row for LOOP AT
找出所有 LOOP AT … INTO 之处,理论上这些地方都可以用 LOOP AT … REFERENCE INTO 或者 ASSIGNING <fs> 替换。当内表的行结构体字段很多时,使用后两种方式可以获得一些性能的提升。
Low-Perform. Parameter Transfers – 检测所有参数传递使用 ”Pass by Value” 之处
Jerry 关注了很多技术公众号,发现参数传递的 ” 传引用 ” 和 ” 传值 ” 这两种方式的辨析,至今仍然是很多互联网公司的面试题之一。
这个选项可以让您指定针对何种类型的参数进行参数传递方式的扫描:
在 ABAP 里理论上采用引用传递的方式进行参数传递,性能上总是优于值传递,具体性能会提高多少,依赖于具体传递的参数类型,无法一概而论。
Security Check – Dynamic and Client-Specific accesses in SELECT – 动态 SQL 语句的检测
符合下列范式的动态 SQL 会被扫描出来:
Dynamic table accesses: SELECT * FROM (dbtab) WHERE …
Dynamic WHERE conditions: SELECT * FROM dbtab WHERE (where_cond)
Accesses to certain tables: SELECT * FROM dbtab WHERE …
Client-specific accesses: SELECT * FROM dbtab FROM WA … CLIENT SPECIFIED …
这个选项并不是禁止您使用动态 SQL 语句——事实上 SAP 应用的持久层里有大量的动态 SQL 语句的使用例子——而是提醒您别忘记了进行 SQL 注入的预防措施:一旦扫描出来,如果有用户输入参与了这些动态 SQL 语句的拼接,那就别忘记看看上下文有没有使用 CL_ABAP_DYN_PRG 对用户输入进行处理。
Search for APPEND and INSERT … INDEX in SORTED Tables
检测所有在有序内表上施加了 APPEND 操作的地方。有了这个扫描选项,能够帮助您避免下图第 13 行这种类型的运行时错误。
Check of SY-SUBRC Handing – ABAP 关键字调用后系统变量 sy-subrc 的检测
Jerry 至今仍清楚地记得,十多年前上研究生课程《UNIX 环境高级编程》时,老师不断地强调在进行系统调用之后一定要检查返回值并进行相应的错误处理。在 Jerry 看来,错误检测和处理是每一位编程人员都应该具备的基本素养。
对应到 ABAP 里,就意味着每次调用 ABAP 的关键字完成某项操作后,都必须检查 sy-subrc 的值来确认这次操作是否成功。
当然也可以根据项目的实际情况,告诉 Code Inspector 只检查某些类型的 ABAP 关键字调用。比如上图意思就是只检查 READ TABLE 关键字调用后是否进行了 sy-subrc 的检查。
Missing table content check before calling SELECT … FOR ALL ENTRIES IN
在使用 FOR ALL ENTRIES IN <itab> 之前,必须先检查内表 itab 是否为空。这个选项能扫描出没有按照这个规范来编写的代码。
Programming Conventions – Naming conventions
在这个界面里为 ABAP 里不同类型的变量设置好您团队里达成一致的命名规范,然后 Code Inspector 就能把代码里所有违反了这些命名规范的地方扫描出来。
Metrics and Statistics
这个检查类别下面的设置都是一些很有意思的统计信息。
还是举例说明。下图红色区域的设置,意思是如果一个类的方法内的可执行语句行数超过 150 行,Code Inspector 就报一条警告消息。这是为了避免大家写出一个过于冗长的方法。
而蓝色区域的设置是如果每 100 行可执行代码的对应注释量小于 10 行,就报一条警告消息。这些阀值可以根据实际情况自行修改或关闭。
FAN-OUT Structural Metrics – 统计一个方法的扇出值
方法的扇入值和扇出值在模块化编程的上下文会经常被提及,这对概念不是编程界首创的,而是源自半导体行业里的逻辑电路设计:
逻辑门的扇出系数定义了该门能够驱动的数字信号输入的最大量,而一个代码模块的扇出值则代表了其直属下层的模块个数。
这个选项能够统计您方法的扇出系数。扇出系数太小,意味着该方法基本没有调用其他下层的函数,这有两种可能:
- 该方法的逻辑本身非常简单,只有两三行代码,比如类的 setter/getter 方法;
- 这个方法的模块化没有做好,存在优化的空间,比如某些直接写在方法内的语句,可以提炼成下层函数并在方法内调用。
Comment Language Metrics
这个选项可以统计代码中出现的德文注释的函数。
Jerry 不太明白该选项有什么用处,给非德国 ABAP 开发人员吐槽用的么?
OO Size Metrics
这个选项也是为了防止您不经意间就创造出怪兽级的类 (monster class) 而生的:一旦您关注的类的属性超过设置的阀值,比如类的成员,类的公 / 私有方法等关注点超过选项里设置的值时,Code Inspector 就会报警。
Program Complexity Test – cyclomatic complexity – 代码环复杂度 (圈复杂度) 的测试利器
这又是一个能帮助您写出 Clean ABAP code 的强大工具。
什么是代码的环复杂度?
根据维基百科的定义,我们把一段代码的执行流画成一张有向无环图,然后环复杂度可以通过下面的公式计算出来:
https://en.wikipedia.org/wiki…
环复杂度 = 图的边数 – 图的节点数 + 2
这其实就是我们研究生专业课《图论》里学的欧拉定理。
看下面这个例子:
上面这 8 行 ABAP 代码,环复杂度为 3,怎么计算出来的?
先把其对应的有向无环图画出来:
这张图的边数为 3,即图中黑色,红色和绿色三条粗线。
这张图的顶点数为 2,如图中两个菱形的蓝色图例所示。
最后环复杂度为 3 – 2 + 2 = 3.
统计表明,代码的高环复杂度和高故障率之间存在很强的正相关性,这不难理解,代码的环复杂度越高,意味着里面嵌套的 IF-ELSE,SWITCH 等逻辑越多,无论是代码原来的开发人员,还是后来接手的维护人员,读起来都会觉得头昏脑胀。
因此大家可以多用 ABAP Code Inspector 的这个扫描选项,随时监控您代码的环复杂度。
Search DB Operations
把您关注的在代码中出现的 SQL 操作关键字全部罗列出来。
Search ABAP Statement Patterns
这个选项也很有用,能根据您指定的正则表达式扫描 ABAP 代码。
例如,您希望找出代码里所有出现了 READ TABLE XXX WITH KEY X = X 的地方,只需要在上图的输入框里填入对应的正则表达式,即用 * 代表任意字符串:
READ TABLE WITH KEY = *
然后 ABAP Code Inspector 就会按照我们期望的行为去扫描代码:
ABAP 报表 RS_ABAP_SOURCE_SCAN 也能实现完全一致的功能:
ABAP Code Inspector 的隐藏功能就介绍到这里,希望大家能够好好利用它们,提高您的工作效率和代码质量,感谢阅读。
要获取更多 Jerry 的原创文章,请关注公众号 ” 汪子熙 ”: