寫具有良好風格的ABAP代碼


編程風格是一個經久不衰的話題,大家所公認的事實是:一個良好的編程風格會帶來很多的好處。而對於“良好”的標准,則眾說紛紜,莫衷一是。編程風格在ABAP程序中當然也有着重要的意義,因為很少看到專門針對ABAP編程風格的討論,我決定把我知道的事情總結出來,以拋磚引玉。歡迎看到這篇文章的朋友回復討論。

 

2020.06.16更新:SAP推出了一份很好的styleguides,是一份很好的指導文檔,對代碼風格方面的問題做出了詳細的解釋,糾正了業界流行的很多錯誤實踐,強烈推薦。

2018.01.11更新:本文中提到的大部分內容可以通過Code Inspector進行檢查,Github上面的一個開源檢查項目abapOpenChecks提供了相當全面的檢查,強烈建議讀者使用。相關文檔地址:http://docs.abapopenchecks.org/checks/

 

本文鏈接:http://www.cnblogs.com/hhelibeb/p/6814045.html 

原創內容,轉載請注明

1,大寫與小寫

如我們所知,ABAP是一種大小寫不敏感的語言。這自然會引起一個問題:使用大寫還是小寫?SAP給出的ABAP編輯器為我們提供了4種選項:

  • (全部)大寫
  • (全部)小寫
  • (關鍵字)大寫
  • (關鍵字)小寫

選擇(關鍵字)大寫,讓代碼的其余部分保持小寫,在我看來是一個極為自然的選擇。理由是,一)閱讀大寫字母組成的文本比閱讀小寫字母組成的文本要難。二)程序的讀者通常會對關鍵字極為熟悉(即使不熟悉,也有文檔可看),而作者本人之外的讀者,對作者寫出的非關鍵字不太可能熟悉。這兩個理由使得,相比關鍵字,我們更需要讓代碼的非關鍵字保持良好的可讀性。因此,非關鍵字的小寫是一種必然的選擇。在此基礎上,讓關鍵字保持大寫,可以幫助我們區分關鍵字和非關鍵字。當然,由於關鍵字高亮的功能的存在,也可以不通過大小寫區別它們,所以(全部)小寫同樣是一種可行的選項,部分SAP標准代碼也是這樣的風格。

某些開發者會告訴新人:代碼最好全部大寫,這樣可以避免自己不小些將大寫參數設定為小寫(ABAP中很多字符參數是大寫的)。然而,由於上述的原因,這是一件很糟糕的事情。字符的值的大小寫和代碼的大小寫完全是兩碼事,因為這種理由放棄代碼的可讀性,是不成立的。

2,縮進

據說很多程序員常年為了縮進的問題爭論不休,ABAP開發者在這方面是幸福的,因為SE38的代碼編輯器提供了自動縮進的功能,這使得只要點擊“格式優化”,所有人的代碼會得到同樣的縮進...

我還沒有使用過新的編輯器——ABAP Development Tools for Eclipse。也許在這個新的IDE普及之后,人們會對ABAP的縮進產生新的看法。

3,表達式vs關鍵字

ABAP是一門包含有大量關鍵字的語言。SAP似乎意識到了關鍵字過多帶來的不便,在嘗試着在近期的更新中引入更多表達式的寫法。

表達式的寫法比關鍵字更加簡潔、可讀,推薦盡量使用表達式代替關鍵字,比如:

"實例化對象

 DATA(e_receiver) = NEW event_receiver( )."推薦的寫法

 DATA e_receiver TYPE REF TO event_receiver. "不推薦的寫法
 CREATE OBJECT e_receiver.

 

*調用方法(可以看到,傳統的寫法居然要5行...
val = object->method( parameter = a ) "建議的寫法

CALL METHOD object->method  "不建議的寫法
    EXPORTING 
       parameter = a 
    RECIEVING
       return    = val.
*訪問內表
SELECT * INTO TABLE @DATA(itab) FROM sflight
  UP TO 10 ROWS ORDER BY carrid.

TRY.
    DATA(ls_sflight) = itab[ 2 ].   "推薦的寫法
  CATCH cx_sy_itab_line_not_found.

ENDTRY.

DATA(ls_sflight) = value #( itab[ 2 ] optional ). "更推薦的寫法 ,value表達式可以自動捕捉異常
DATA ls_sflight TYPE sflight. READ itab INTO ls INDEX 2. "不推薦的寫法 IF sy-subrc <> 0. ENDIF.

 有關更多表達式寫法的例子可以參考這個博客:ABAP 7.4新特性,或者ABAP Objects,以及SAP的官方文檔。

4,Open SQL

 如果要從一個數據庫表中取得它自身的兩個字段比較后的到的條目,ABAP的新手可能會這樣寫:

SELECT carrid connid fldate seatsocc seatsmax
       FROM sflight
       INTO TABLE sflight_tab
       WHERE seatsmax < sflight-seatsocc.

而有經驗的/看過文檔的人知道上面的代碼會報錯,正確的寫法是這樣:

SELECT carrid connid fldate seatsocc seatsmax
       FROM sflight
       INTO TABLE sflight_tab
       WHERE seatsmax < sflight~seatsocc.

區別就在與-和~。

 

不過第一種寫法在某些情況下也是可以運行的,如果程序中有這樣的聲明的話:

DATA:
  BEGIN OF sflight,
    carrid   TYPE sflight-carrid,
    connid   TYPE sflight-connid,
    fldate   TYPE sflight-fldate,
    seatsocc TYPE sflight-seatsocc,
    seatsmax TYPE sflight-seatsmax,
  END OF sflight,
  sflight_tab LIKE STANDARD TABLE OF sflight WITH EMPTY KEY.

此時程序也可以運行,不過比較不會發生在數據庫字段之間,而是會以本地定義的結構sflight中的seatsocc作為條件。

 

要避免這類混淆的發生,可以使用轉義字符@,加在SQL語句中的Host Variables前面。

如果是想比較數據庫內的字段的話:

SELECT carrid, connid, fldate, seatsocc, seatsmax
       FROM sflight
       WHERE seatsmax < sflight~seatsocc
       INTO TABLE @sflight_tab.

而如果是想要以ABAP程序內的值作為條件的話,就要在它的前面也加上@:

SELECT carrid, connid, fldate, seatsocc, seatsmax
       FROM sflight
       WHERE seatsmax < @sflight-seatsocc
       INTO TABLE @sflight_tab.

這樣就不會混淆了~

(注:本節的內容來自一篇英文博客:Why the new Open SQL Syntax is Better

此外,在S4/HANA中,SAP推薦將更多的計算內容放到數據庫中。為了實現這一目的,現在Open SQL具有CASE表達式、字符串表達式、CAST、CTE等多種新功能。我們應該嘗試使用它們。

5,命名法

 ABAP程序通常使用一系列前綴來為變量命名,比如:

LT_ = Local internal table

LS_ = Local structure(work area)

LR_ = Local reference

GT_ = Global internal table

GS_ = Global structure(work_area)

GR_ = Global reference

這樣做是有好處的,一方面,通常的ABAP編輯器不具備自動提示類型的功能,合理前綴可以降低閱讀代碼的心智負擔;另一方面,如上一節所述,如果為變量取一個和數據類型/數據庫字段完全相同的名字,會在某些情況下產生意外的混淆。比如:

DATA s1 LIKE sflight.
DATA s2 TYPE sflight.
"以上這段代碼會聲明兩個相同的結構s1, s2


DATA sflight TYPE i.

DATA s1 LIKE sflight.
DATA s2 TYPE sflight.
"如果聲明過一個名為sflight的i類型變量,則使用like的語句會聲明一個i類型的s1,使用type的語句會聲明一個有着sflight行類型的結構s2..

 

但是前綴的濫用也會導致很多問題,合理的ABAP代碼中應該盡量避免多余的變量名前綴。

比如

  • l_carrid(較好)
  • lv_carrid(較差)

使用lv/gv的前綴來表示本地變量/全局變量,是一個比較不明智的做法。因為,一個變量是值這種事情通常是無需說明的。v可以被當作默認值省略,而lt/lc則有意義。

同樣的,為form命名時也不應當存在這種無意義的前綴:

  • get_price(正確)
  • frm_get_price(錯誤)

因為通常來說,form的使用是通過PERFORM關鍵字來實現的:

PERFORM get_price.

這時,get_price顯然不可能是form之外的任何存在。使用frm_這樣的前綴,不能帶來任何理解上的幫助,只會增加代碼閱讀的難度。

2019.07.23更新:

QQ群里有群友質疑:lv_是通行的命名前綴,l_會帶來混淆,讓開發者感到困惑。

在這里回應下,首先,這種命名方式並不是筆者的發明,

sap的很多代碼中的變量會用l_或m_作為前綴,比如我們最常用的cl_gui_alv_grid中的一些成員變量的前綴就是m_。筆者只是認同這種辦法的合理性。

在命名中,前綴后面的東西比前綴重要很多,所以要盡可能降低前綴的復雜性,避免浪費讀寫代碼的時間。使用l_而非lv_可能會稍微增加命名上的復雜性,但是如果開發者可以在一開始掌握一個稍微復雜點的規則,也許可以在后面省更多力氣。

SAP的最新建議不要使用前綴,這也證明了前綴的重要性遠不及變量名的主體的重要性。

6,單行長度

 有種觀點認為,單行的代碼長度不應超過80個字符。大體上,對於ABAP代碼而言,我同意這個觀點。

80個字符在ABAP編輯器中的視覺效果

 

如圖,80個字符已經稍稍超出了編輯器核心區域的邊界(雖然遠未達到ABAP支持的單行最大長度——255字符)。如果只是打開單個編輯器窗口的話,這種長度還可以接受,但如果要並排打開2個窗口,一部分代碼也許會無法直接顯示。

此外,在SAP自身的代碼比較工具中,過長的單行內容是無法直接展示的:

過長的單行代碼不能一次展示

這種情況下,需要點擊工具欄中的按鈕換頁:,非常不利於閱讀。如果能有意限制單行代碼的長度,就可以避免處於這種不利的情況。

7,帶表頭的內表

也許每個ABAP初學者學習的第一樣東西都是內表,而學習內表時要學會的首要事項就是工作區、帶表頭的內表與不帶表頭的內表的區別....會有教程告訴他們用OCCURS關鍵字聲明一個帶表頭的內表,

DATA: BEGIN OF lt_numbers OCCURS 0,
        num1 TYPE i,
        num2 TYPE i,
      END OF lt_numbers.

或者這樣,使用WITH HEADER LINE,

DATA: lt_sflight TYPE STANDARD TABLE OF sflight WITH HEADER LINE.

如果這樣做的話,聲明得到的內表就會代表兩樣東西,比如,lt_sflight實際上代表着作為表頭的結構lt_sflight、和內表本身lt_sflight[],至於在具體的代碼中它到底代表哪個,只能由語境和開發者的意圖決定...

這種奇怪的特性似乎是為了開發人員的方便而設計的,但在生產實踐上,它使得開發者極易不慎將一個名稱代表的兩個實體混用,從而寫出有bug的代碼。SAP在意識到自己的錯誤之后,把這兩種聲明方式標記為過時的語法,並且在OO模式下,會在語法檢查中提示這一點。

然而,為了兼容舊有的程序,在report和function group等類型的程序中,人們依然可以使用這兩種方式聲明帶表頭的內表。很多古老的ABAP教程也大量地使用了它們。以至於不少新人無意識地把它們當作聲明內表的合理方式。聽說某些公司在規范中禁止了它們的使用,在2017年的現在,我認為這是一項非常合理的舉措,用同一個名字代表兩樣不同的東西本來就是很不好的事情。為了讓書寫者不至於混淆、為了讓讀者更好的理解代碼,請放棄帶表頭的內表。與之類似的tables關鍵字,也應避免使用。

 

 

參考: ABAP Programming Guidelines

    BEST PRACTICE GUIDELINES FOR DEVELOPMENT – USEFUL TIPS FOR ABAP DEVELOPMENT

   

 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM