ABAP 代码整洁之道的代码格式化准则

401 阅读6分钟

前言

编写可阅读代码是开发人员软技能的一部分,这一篇文章将介绍 ABAP 代码整洁之道中的代码格式化法则。

代码格式化准则

格式统一

以相同的格式化项目的所有代码。让所有团队成员使用相同的格式化代码,如果编辑外部代码,遵循该项目的格式化风格,而不是坚持自己的个人风格。

为了方便阅读,而不是编写代码进行优化

的确,在实际开发过程中,开发人员花费大量时间阅读代码的时间远远超过编写代码,所以我们应该针对读取和调试方便来优化我们的代码格式,例如有限采用这种定义:

DATA:
    a TYPE b,
    c TYPE d,
    e TYPE f.

而不是

" 反模式写法
DATA:
  a TYPE b
  ,c TYPE d
  ,e TYPE f.

激活前使用系统的格式优化器

在激活对象前应用格式优化器——SE80SE24 和 ADT 中的 Shift+F1

如果修改一个大型未格式化旧代码库,可能需要仅对选定行应用格式优化器,以避免产生大量的变更项和传输依赖项。请考虑在单独的传输请求或注释中整齐打印完整的开发对象。

使用团队设置的格式优化器

始终使用团队设置。在 菜单 > 实用程序 > 设置 ...  > ABAP 编辑器 > 格式优化器 下进行指定。

按照团队的协商设置缩进转换大写/小写 > 大写关键字

image.png

每行一条语句

采取这样的方式:

DATA do_this TYPE i.
do_this = input + 3.

而不是:

DATA do_this TYPE i. do_this = input + 3.

保持合理的行长度

遵守最多 120 个字符的行长度。

如果行距不是很宽,人眼可以更舒适地阅读文字——请在 UI 设计师或眼动研究人员建议下做出您的选择。在调试或比较相邻的两行源代码时,如果代码行更窄一些,您会心生感激之情的。

老的终端设备的 80 个甚至 72 个字符的限制太过严格了。虽然通常建议使用 100 个字符(这是一个可行的选择),但对于 ABAP 来说,最好使用 120 个字符,这可能是因为这种语言一般较为冗长。

紧凑代码

使用满足语法的空格,例如:

DATA(result) = calculate( items ).

而不是添加不必要的空格:

" anti-pattern
DATA(result)        =      calculate(    items =   items )   .

添加单一空行来分隔内容,而不要添加多行

DATA(result) = do_something( ).

DATA(else) = calculate_this( result ).

强调这两条语句做的是不同的事情。但没必要

" anti-pattern
DATA(result) = do_something( ).



DATA(else) = calculate_this( result ).

添加分隔空行可能表明您的方法没有在做一件事

勿因分隔空行产生困扰

使用:

METHOD do_something.
  do_this( ).
  then_that( ).
ENDMETHOD.

没有理由养成用空行将代码分开的坏习惯

" anti-pattern
METHOD do_something.

  do_this( ).

  then_that( ).

ENDMETHOD.

空行实际上仅在您有跨越多行的语句时才有意义

METHOD do_something.

  do_this( ).

  then_that(
    EXPORTING
      variable = 'A'
    IMPORTING
      result   = result ).

ENDMETHOD.

对齐同一对象而非不同对象的赋值

为了强调这些事物在某种程度上是属于一起的

structure-type = 'A'.
structure-id   = '4711'.

或者这样更好

structure = VALUE #( type = 'A'
                     id   = '4711' ).

而对于那些彼此无关的事物,仍保留参差不齐的状态:

customizing_reader = fra_cust_obj_model_reader=>s_get_instance( ).
hdb_access = fra_hdbr_access=>s_get_instance( ).

在行尾使用游括号

modify->update( node           = if_fra_alert_c=>node-item
                key            = item->key
                data           = item
                changed_fields = changed_fields ).

而不是毫无必要地加长,另起一行并不推荐,虽然符合 ABAP 语法:

" 不推荐
modify->update( node           = if_fra_alert_c=>node-item
                key            = item->key
                data           = item
                changed_fields = changed_fields
).

保持单参数调用于一行

DATA(unique_list) = remove_duplicates( list ).
remove_duplicates( CHANGING list = list ).

而不是毫无必要地加长

" 不推荐
DATA(unique_list) = remove_duplicates(
                           list ).
DATA(unique_list) = remove_duplicates(
                         CHANGING
                           list = list ).

保持参数在调用之后

image.png

DATA(sum) = add_two_numbers( value_1 = 5
                             value_2 = 6 ).

如果这造成行很长,可以换行,将参数转到下一行:

DATA(sum) = add_two_numbers(
               value_1 = round_up( input DIV 7 ) * 42 + round_down( 19 * step_size )
               value_2 = VALUE #( ( `Calculation failed with a very weird result` ) ) ).

如果换行,则在调用下保持参数缩进

DATA(sum) = add_two_numbers(
                   value_1 = 1
                   value_2 = 2 ).

在其他地方对齐参数将导致很难发现它们所属的对象:

DATA(sum) = add_two_numbers(
    value_1 = 1
    value_2 = 2 ).

但是,如果要避免因名称长度更改而破坏格式,这就是最佳模式了。

例如,不推荐:

DATA(sum) = add_two_numbers(
                   value_one_parameter = 1
                   value_2 = 2 ).

将多个参数换行

image.png

DATA(sum) = add_two_numbers( value_1 = 5
                             value_2 = 6 ).

是的,这浪费了空间。但是如果不这样,就很难确定一个参数在哪里结束而下一个在哪里开始:

" 不推荐
DATA(sum) = add_two_numbers( value_1 = 5 value_2 = 6 ).

参数对齐

modify->update( node           = if_fra_alert_c=>node-item
                key            = item->key
                data           = item
                changed_fields = changed_fields ).

边距参差不齐,使得很难看到参数的结束位置以及参数值的开始位置:

" 不推荐
modify->update( node = if_fra_alert_c=>node-item
                key = item->key
                data = item
                changed_fields = changed_fields ).

如果调用行过长则将其换行

DATA(some_super_long_param_name) =
  if_some_annoying_interface~add_two_numbers_in_a_long_name(
      value_1 = 5
      value_2 = 6 ).

缩进并卡到制表位

将参数关键字缩进 2 个空格,并将参数缩进 4 个空格:

DATA(sum) = add_two_numbers(
              EXPORTING
                value_1 = 5
                value_2 = 6
              CHANGING
                errors  = errors ).

如果没有关键字,则将参数缩进 4 个空格。

DATA(sum) = add_two_numbers(
                value_1 = 5
                value_2 = 6 ).

使用 Tab 键缩进。就算多加了一个空格也没有关系。不要强调开发人员增加当个空格。

(如果左侧 DATA(sum) = 部分的字符数非偶数,则会发生这种情况。)

如同方法调用那样缩进内联声明

按照与方法调用相同的方式,使用 VALUENEW 缩进内联声明:

采取:

merge( a = VALUE #( b = 'X'
                    c = 'A' ) ).

DATA(result) = merge_structures( a = VALUE #( field_1 = 'X'
                                              field_2 = 'A' )
                                 b = NEW /clean/structure_type( field_3 = 'C'
                                                                field_4 = 'D' ) ).

勿对齐类型声明子句 type

DATA name TYPE seoclsname.
DATA reader TYPE REF TO /clean/reader.

变量及其类型属于同一类,因此从视觉上来说应将其分为一组。将 TYPE 子句对齐会使人们的分心,并建议这些变量形成一个垂直组,而它们的类型形成一个垂直组。

对齐还会产生不必要的编辑开销,当最长变量名的长度发生变化时,需要调整所有的缩进。

" 不推荐
DATA name   TYPE seoclsname.
DATA reader TYPE REF TO /clean/reader.

这一点在实际过程中,不必强调将 TYPE 语句对齐,例如:

DATA:gr_grid TYPE REF TO cl_gui_alv_grid.  
DATA:gs_stbl TYPE lvc_s_stbl.  
DATA:gcl_alv_grid TYPE REF TO cl_gui_alv_grid,  
     gc_grid      TYPE REF TO cl_gui_alv_grid.

总结

现代开发语言都有自己的代码格式化规则,比如 Python 代码风格指南 PEP 8,Go 语言的 gofmt,如果格式化错误,会导致编译出错,虽然 ABAP 没有严格的格式化规则限制,但是以上的准则可以帮助我们编写更符合阅读的高质量代码,希望能对你有用,不说了,我也去重构自己写的 shi 一样的代码去了。