
Clean Code Guidelines in the SAPABAP environment – do I really care?
Reading time: 6 min
A contribution by Alexander Vogel
In 2008, Robert C. Martin wrote his book on clean code “Clean Code: Refactoring, Patterns, Testing and Techniques for Clean Code” and thus coined this term.
In April 2019, SAP introduced a Clean Code style guide for ABAP developers to use as a guide for developers and teams. This style guide is an adaptation of Robert C. Martin’s book and covers all the important points in the ABAP environment.
Today, over 2 years later we are now asking ourselves the questions “what exactly is clean code?”, “should we rebuild legacy code?” and most importantly “do we need clean code?”. We will now address these questions here and look at small examples. So …
What is Clean Code?
Clean Code is not a strict set of rules, rather a philosophy guided by the following principles:
/ KISS (Keep it simple, stupid)
Keep your code simple. One method should do one thing at a time.
/ DRY (Don’t repeat yourself)
Do not repeat your code. Store it in a method to use it again.
/ YAGNI (You aren’t gonna need it)
Do not introduce additional functionality until you need it.
/ Readability before conciseness (Readability before conciseness)
Others should be able to understand your code – as soon as possible!
It is advisable to start with simple points, such as applying the KISS principle and breaking down methods to individual activities. Reduce the complexity and check if the code is not easier to present.
Nice… is there also an example?
We look at two code snippets with ultimately the same effect. The second snippet shows the clean code approach, which is much easier to read – most clearly illustrated in the “add_mail” method.
What do we change in the legacy code, apart from the above rules, to get to Clean Code:
Hungarian notation
In the 1990s, Charles Simonyi invented the Hungarian notation in which variables were prefixed to show their origin and data type. In addition, variables were kept as short as possible to be efficient for the compilers. Declarations of variables were mostly provided with comments to express what the variable does.
Since we have access to more efficient, faster and better compilers nowadays, we can do without this and name the variables directly after what they are supposed to do.
Naming – basic rules
Variables:
Small scope -> Short variable name
Large scope -> Long variable name
Classes/Methods
Small scope -> Long name & Private
Large scope -> Short name & if applicable Public
IF statements
The nesting of IF-statements should be kept as small as possible to keep the overview. If several cases of “IF / IFELSE / ELSE” should be used, one should fall back to the KISS rule and if necessary extract several methods from it.
Field symbols or references?
This point is currently still under discussion, the guidelines suggest a syntax à la LOOP … REFERENCE INTO DATA(…). before. However, if you use field symbols (à la LOOP … ASSIGNING FIELD-SYMBOL().) this benefits the runtime. Here there is an improvement of up to 13%!
Avoid loops
Loops – especially loop in loop – should be avoided as much as possible, as they result in extreme running times. If only one entry is required, the line can be selected directly.
Avoid READ TABLE
Better than looping to get a single row is READ TABLE. However, direct access to the row of the table is even better. Here is an example:
TRY.
DATA(row) = my_table[ key = input ].
CATCH cx_sy_itab_line_not_found.
" Do something
ENDTRY.
Example Legacy Code
Here is finally some code, but legacy code is not really “pretty”, well readable and not maintainable:
DATA: gt_pernr_tab TYPE TABLE OF pernr_d,
gs_pernr TYPE pernr_d,
gs_pa0001 TYPE pa0001,
gt_pa0001 TYPE TABLE OF pa0001,
gs_pa0002 TYPE pa0002,
gs_pa0105 TYPE pa0105.
LOOP AT gt_pernr_tab INTO gs_pernr.
SELECT * FROM pa0001
APPENDING TABLE gt_pa0001
WHERE pernr EQ gs_pernr
AND begda LE sy-datum
AND endda GE sy-datum.
ENDLOOP.
SORT gt_pa0001 BY pernr begda.
DELETE ADJACENT DUPLICATES FROM gt_pa0001.
LOOP AT gt_pa0001 INTO gs_pa0001.
SELECT SINGLE * FROM pa0002
INTO gs_pa0002
WHERE pernr EQ gs_pa0001-pernr
AND begda LE sy-datum
AND endda GE sy-datum.
IF sy-subrc EQ 0.
SELECT SINGLE * FROM pa0105
INTO gs_pa0105
WHERE pernr EQ gs_pa0001-pernr
AND subty EQ '0010'
AND begda LE sy-datum
AND endda GE sy-datum.
IF sy-subrc NE 0.
MOVE-CORRESPONDING gs_pa0001 TO gs_pa0105.
CONCATENATE gs_pa0002-vorna '.' gs_pa0002-nachn '@mail.test' INTO gs_pa0105-usrid_long.
INSERT pa0105 FROM gs_pa0105.
ENDIF.
ENDIF.
ENDLOOP.
Clean Code Example
In contrast, clean code can be read, maintained and understood very well. It’s best when you can read it like prose. For the representation as clean code I have chosen here the form of a class with methods:
CLASS change_mail DEFINITION FINAL CREATE PRIVATE.
PUBLIC SECTION.
METHODS: add_mails IMPORTING i_personnel_numbers TYPE pernr_tab.
PRIVATE SECTION.
METHODS:
add_mail IMPORTING i_personnel_number TYPE pernr_d,
read_personal_data IMPORTING i_personnel_number TYPE pernr_d
RETURNING VALUE(r_personnel_data) TYPE pa0002,
does_mail_already_exist IMPORTING i_personnel_number TYPE pernr_d
RETURNING VALUE(r_exists) TYPE boolean,
write_new_mail_to_database IMPORTING i_personnel_data TYPE pa0002.
ENDCLASS.
CLASS change_mail IMPLEMENTATION.
METHOD add_mails.
LOOP AT i_personnel_numbers ASSIGNING FIELD-SYMBOL(<personnel_number>).
add_mail( <personnel_number> ).
ENDLOOP.
ENDMETHOD.
METHOD add_mail.
DATA(personnel_data) = read_personal_data( i_personnel_number ).
IF does_mail_already_exist( i_personnel_number ).
write_new_mail_to_database( personnel_data ).
ENDIF.
ENDMETHOD.
METHOD read_personal_data.
SELECT SINGLE * FROM pa0002
INTO r_personnel_data
WHERE pernr EQ i_personnel_number
AND begda LE sy-datum
AND endda GE sy-datum.
ENDMETHOD.
METHOD does_mail_already_exist.
CONSTANTS: mail_subtyp TYPE subty VALUE '0010'.
DATA: exists(1).
SELECT SINGLE 'X' FROM pa0105
INTO @exists
WHERE pernr EQ @i_personnel_number
AND subty EQ @mail_subtyp
AND begda LE @sy-datum
AND endda GE @sy-datum.
IF sy-subrc EQ 0 AND exists EQ 'X'.
r_exists = abap_true.
ELSE.
r_exists = abap_false.
ENDIF.
ENDMETHOD.
METHOD write_new_mail_to_database.
DATA(communication) = CORRESPONDING pa0105( i_personnel_data ).
communication-usrid_long =
|{ i_personnel_data-vorna }.{ i_personnel_data-nachn }@mail.test|.
INSERT pa0105 FROM communication.
ENDMETHOD.
ENDCLASS.
What do we do with legacy projects?
SAP recommends the following four-step plan in its style guide for legacy projects:
- Get the team on board. Communicate and explain the new style, and make sure every member of the project team agrees. You don’t have to write down all the policies at once. Just start with a small undisputed sub-area and develop from there.
- In your daily work routine, follow the Boy Scout rule of “leave the campsite cleaner than you found it.” In terms of clean code:Always leave the code better than you found it. Don’t overdo it by spending hours “cleaning up the entire campsite.” Just spend a few extra minutes and watch the improvements accumulate over time.
- Build clean islands from time to time: Select a small object or component and try to make it “clean” in all aspects. These islands demonstrate the utility of what you are doing and provide a reliably tested basis for further refactoring.
- Talk about it. Whether you’re setting up old-school Fagan code inspections, or hosting info sessions or forum discussions in your favorite chat tool: You need to talk about your experiences and what you’ve learned so that a common understanding can grow within your team.
So, when we replace old code, we should do it step by step and look for small “islands”, so that over time, all the coding can be converted to clean code.
So if you are bug fixing, you should change this place directly to clean code to avoid duplicate work. Again as a short rule of thumb: Bugfixing only in clean code.
So then… do we need clean code?
Short answer: YES!
Longer answer: Definitely! Because we make our code more readable – for us and others. The code becomes maintainable and reusable, and most importantly, more stable! A method treats, ideally only one thing and describes itself. Thus, for example, comments are invalid or a bug fix does not accidentally damage another part of the software.
Cheat Sheet & Golden Rules
Finally, here are the SAP cheat sheets for Clean Code, as well as the golden rules that SAP issues for this. They are not 100% complete, but give a very good overview of the subject. This way, each team member can quickly learn the most important points. It is best to download this directly as sources for better readability:
The easiest address for good code: SAP Gold Partner
How convenient that we are one. Our SAP division is made up of highly motivated experts in consulting and development who do awesome shit with SAP SuccessFactors, HCM and 4HANA for our customers. Together, we managed to achieve the SAP Gold Partnership in just under a year.
We look forward to your ideas, questions and project suggestions. Just send us a mail to hello@mmmake.com.