Sei sulla pagina 1di 4

Clean ABAP General + Comments + Formatting

Names Comments Formatting


Use descriptive names Express yourself in code, not in Be consistent
max_wait_time_in_seconds, iso3166tab. comments Same style throughout a project
assert_is_valid( input ) Optimize for reading, not for writing
Prefer solution domain and problem “checks whether user input is valid DATA: a
domain terms check( x ) , b.
Business layers: account, ledger
Comments are no excuse for bad Use the Pretty Printer before activating
Technical layers: queue, tree
names Use your Pretty Printer team settings
Use plural DATA total_sum
No more than one statement per line
" the total sum
E.g. countries instead of country don’t( ). do_this( ).
DATA s
Use pronounceable names Use methods instead of comments to Stick to a reasonable line length
detection_object, dobj <= 120 characters
segment your code
Avoid abbreviations do_a( ).
do_b( ).
Condense your code
customizing, cust No whitespace in weird places
" do a
a = b + 1.
Use same abbreviations everywhere " do b Add a single blank line to separate
dobjt, dot, dotype x = a / 10. things, but not more
Use nouns for classes and verbs for Write comments to explain the why, No whitespace in weird places
methods not the what Don’t obsess with separating blank
account, withdraw, is_empty " can be missing if …
" reads the itab lines
Avoid noise words READ TABLE itab No whitespace in weird places
data, controller, object
Design goes into the design Align assignments to the same object,
Pick one word per concept documents, not the code but not to different ones
read, retrieve, query " some general observations on this structure-type = 'A'.
structure-id = '4711'.
Use pattern names only if you mean Comment with ", not with *
" inlines nicely Close brackets at line end
them * aligns to weird places updater->update( this
E.g. factory, façade, composite ).
Put comments before the statement
Avoid encodings, esp. Hungarian Keep single parameter calls on one line
they relate to just_like( that )
notation and prefixes " right here
result = a + b do_it( ). " not there
rv_result = iv_a + iv_b " nor there
Keep parameters behind the call
break_only(
if_the_line_gets_too_long ).
Delete code instead of commenting it
" READ TABLE
If you break, indent parameters under
Language Use FIXME, TODO, and XXX and add the call
DATA(sum) = add_two_numbers(
Mind the legacy your ID value_1 = 5
" FIXME FH check sy-subrc! value_2 = 6 ).
Try new syntax before applying

Mind the performance Don’t add method signature and end- Line-break multiple parameters
Measure potentially slower patterns of comments add_two_numbers( a = 5 b = 6 ).
ENDIF. " IF a = 0.
Prefer object orientation over Align parameters
Don’t duplicate message texts as
procedural programming
I.e. classes over functions and reports
comments
" Business document not found Break the call to a new line if the line
Prefer functional over procedural MESSAGE e100. gets too long
DATA(result) =
language constructs ABAP Doc only for public APIs some_object->some_interface~a_method(
E.g. index += 1 or index = index + 1 PRIVATE SECTION. a = 1
Instead of ADD 1 to index "! Reads something b = 2 ).
METHODS read_something
Avoid obsolete statements Indent and snap to tab
MOVE 42 to b. Don’t force people to add single spaces
Use design patterns wisely Indent in-line declarations like method
I.e. where appropriate
calls
merge( a = VALUE #( b = 'X'
c = 'A' ) ).

Don’t align type clauses


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

Clean ABAP Cheat Sheet v1.4.1 PUBLIC https://github.com/SAP/clean-abap/blob/master/cheat-sheet/CheatSheet.md


Clean ABAP Variables + Statements + Classes
Constants Booleans Classes: Object orientation
Use constants instead of magic Use Booleans wisely Prefer objects to static classes
numbers Enumerations often make more sense
E.g. typekind_date instead of 'D'
Use ABAP_BOOL for Booleans Prefer composition over inheritance
Prefer enumeration classes over DATA has_entries TYPE abap_bool or DATA delegate TYPE REF TO
BOOLE_D where DDIC type needed CLASS a DEFINITION INHERITING FROM
constants interfaces
E.g. class message_severity over interface Use ABAP_TRUE and ABAP_FALSE for Don’t mix stateful and stateless in the
common_constants same class
comparisons
If you don’t use enumeration classes, Instead 'X' , space, and IS INITIAL
group your constants Use XSDBOOL to set Boolean variables
Don’t mix unrelated constants in same structure empty = xsdbool( itab IS INITIAL )
Classes: Scope
Global by default, local only in
Variables Conditions exceptional cases
CLASS lcl_some_helper
Prefer inline over up-front declarations Try to make conditions positive
DATA(name) = 'something' FINAL if not designed for inheritance
IF has_entries = abap_true.
DATA: name TYPE char30
CLASS a DEFINITION FINAL
Don’t declare inline in optional Consider decomposing complex
conditions Members PRIVATE by default,
branches DATA(example_provided) = xsdbool(…) PROTECTED only if needed
IF has_entries = abap_true.
IF example_provided = abap_true AND PRIVATE SECTION.
DATA(value) = 1.
one_example_fits = abap_true. DATA attribute
Do not chain up-front declarations Consider extracting complex conditions Consider using immutable instead of
DATA name TYPE seoclsname.
IF is_provided( example ).
DATA reader TYPE REF TO something. getter
CLASS data_container
Prefer REF TO over FIELD-SYMBOL DATA a TYPE i READ-ONLY
LOOP AT itab REFERENCE INTO …
Ifs Use READ-ONLY sparingly
READ-ONLY
No empty IF branches
Tables IF has_entries = abap_true.
ELSE.
Use the right table type Classes: Constructors
Prefer CASE to ELSE IF for multiple
HASHED: large, filled at once, never modified,
read often
alternative conditions Prefer NEW over CREATE OBJECT
CASE type. DATA(a) = NEW b( ).
SORTED: large, always sorted, filled over time or WHEN this.
modified, read often CREATE OBJECT a TYPE b
WHEN OTHERS.
STANDARD: small, array-like ENDCASE.
If your global class is CREATE PRIVATE,
Avoid DEFAULT_KEY Keep the nesting depth low leave the CONSTRUCTOR public
DATA itab TYPE … WITH EMPTY KEY ELSE. CLASS a DEFINITION CREATE PRIVATE.
DATA itab TYPE … WITH DEFAULT KEY IF <other>. PUBLIC SECTION.
ELSE. METHODS constructor
Prefer INSERT INTO TABLE over IF <something>.
APPEND TO Prefer multiple static factory methods
Except to express that row must be last over optional parameters
METHODS constructor
Prefer LINE_EXISTS over READ TABLE Regular expressions IMPORTING
a OPTIONAL
IF line_exists( itab[ key = 'A' ] )
b OPTIONAL
Prefer simpler methods to regular
Prefer READ TABLE over LOOP AT expressions Use descriptive names for multiple
LOOP AT my_table … WHERE key = 'A'.
EXIT. IF input IS NOT INITIAL. constructor methods
IF matches( … regex = '.+' ). METHODS create_from_sample
PREFER LOOP AT WHERE over nested IF Prefer basis checks to regular
METHODS create_from_definition
LOOP AT my_table … WHERE key = 'A'.
expressions Make singletons only where multiple
CALL FUNCTION 'SEO_CLIF_CHECK_NAME' instances don’t make sense
pattern = '[A-Z][A-Z0-9_]{0,29}' DATA singleton
Strings Consider assembling complex regular
expressions
Use ` to define literals CONSTANTS classes …
CONSTANTS a TYPE string VALUE `abc` CONSTANTS interfaces …
… = |{ classes }|{ interfaces }|.
Use | to assemble text
text = |Received { http_code }|

Clean ABAP Cheat Sheet v1.4.1 PUBLIC https://github.com/SAP/clean-abap/blob/master/cheat-sheet/CheatSheet.md


Clean ABAP Methods + Exceptions
Methods: Calls Methods: Parameter number Error handling: Return codes
Prefer functional over procedural calls Aim for few IMPORTING parameters, at Prefer exceptions to return codes
do_it( ). best less than three METHODS check RAISING EXCEPTION
CALL METHOD do_it. METHODS check RETURNING result
METHODS a IMPORTING b c d e
Omit RECEIVING Split methods instead of adding Don’t let failures slip through
DATA(a) = do_it( ). DATA(result) = check( input )
do_it( RECEIVING result = a ). OPTIONAL parameters IF result = abap_false.
METHODS a IMPORTING b
Omit the optional keyword EXPORTING METHODS c IMPORTING d
do_it( a = b ). METHODS x
do_it( EXPORTING a = b ). IMPORTING b
d Error handling: Exceptions
Omit the parameter name in single
Use PREFERRED parameter sparingly Exceptions are for errors, not for
parameter calls METHODS do_it
do_it( b ). IMPORTING a PREFERRED regular cases
do_it( a = b ). B TYPE i RAISE EXCEPTION db_read_failure
RAISE EXCEPTION not_enough_money
RETURN, EXPORT, or CHANGE exactly
Use class-based exceptions
one parameter METHODS do_it RAISING EXCEPTION
Methods: Object orientation METHODS do_it METHODS do_it EXCEPTIONS
EXPORTING a
Prefer instance to static methods CHANGING b
METHODS a
CLASS-METHODS a
Error handling: Throwing
Public instance methods should be part Methods: Parameter types
of an interface Use own super classes
CLASS our_products_static_check
INTERFACES the_interface. Prefer RETURNING over EXPORTING INHERITING FROM cx_static_check
METHODS a METHODS a RETURNING b
METHODS a EXPORTING b
Throw one type of exception
METHODS a RAISING EXCEPTION b c d
RETURNING large tables is usually okay
METHODS a RETURNING b TYPE TABLE
Methods: Method body METHODS a EXPORTING b TYPE TABLE
Use sub-classes to enable callers to
distinguish error situations
Do one thing, do it well, do it only Use either RETURNING or EXPORTING METHODS do_it RAISING EXCEPTION r
CLASS a INHERITING FROM r
or CHANGING, but not a combination CLASS b INHERITING FROM r
Focus on the happy path or error METHODS do_it
EXPORTING a Throw CX_STATIC_CHECK for
handling, but not both CHANGING b
TRY. manageable situations
“ focus here Use CHANGING sparingly, where suited RAISE EXCEPTION no_customizing
CATCH. METHODS IMPORTING … RETURNING …
“ do somewhere else METHODS CHANGING Throw CX_NO_CHECK for usually
ENDTRY.
unrecoverable situations
Split method instead of Boolean input RAISE EXCEPTION db_unavailable
Descend one level of abstraction
do_something_high_level ( ). parameter
DATA(low_level_op) = |a { b }|. METHODS do_it_without_saving Consider CX_DYNAMIC_CHECK for
METHODS do_it_and_save avoidable exceptions
Keep methods small METHODS do_it IMPORTING and_save
RAISE EXCEPTION division_by_zero
3-5 statements, one page, 1000 lines
Dump for totally unrecoverable
situations
Methods: Parameter names RAISE EXCEPTION out_of_memory
Methods: Control flow Prefer RAISE EXCEPTION NEW to RAISE
Consider calling the RETURNING
Fail fast parameter RESULT EXCEPTION TYPE
METHOD do_it. METHODS sum RETURNING result RAISE EXCEPTION NEW a( ).
“ some more actions METHODS sum RETURNING sum RAISE EXCEPTION TYPE a.
CHECK input IS NOT INITIAL.

CHECK or RETURN
METHOD do_it.
CHECK input IS NOT INITIAL.
Methods: Parameter initialization Error handling: Catching
Avoid CHECK in other positions Clear or overwrite EXPORTING Wrap foreign exceptions instead of
LOOP AT itab INTO DATA(row). reference parameters letting them invade your code
CHECK row IS NOT INITIAL. CLEAR et_result. CATCH foreign INTO DATA(error).
RAISE EXCEPTION NEW my( error ).
Don’t clear VALUE parameters RAISE EXCEPTION error.
CLEAR rv_result.

Clean ABAP Cheat Sheet v1.4.1 PUBLIC https://github.com/SAP/clean-abap/blob/master/cheat-sheet/CheatSheet.md


Clean ABAP Testing
Principles Injection Test Data
Write testable code Use dependency inversion to inject test Make it easy to spot meaning
There are no tricks to writing tests, there are only doubles METHODS accepts_emtpy_user_input
tricks to writing testable code. (Google) METHODS test_1
cut = NEW( stub_db_reader )
cut->set_db_reader( stub_db_reader )
Enable others to mock you cut->db_reader = stub_db_reader Make it easy to spot differences
CLASS my_super_object DEFINITION. given_some_data( ).
INTERFACES you_can_mock_this. Use CL_ABAP_TESTDOUBLE do_the_good_thing( ).
assert_that_it_worked( ).
before writing custom stubs and mocks
Readability rules
Use constants to describe purpose and
given_some_data( ). Exploit the test tools
do_the_good_thing( ).
CL_OSQL_REPLACE, CDS Test Framework, Avalon importance of test data
and_assert_that_it_worked( ). CONSTANTS some_nonsense_key …

Don’t make copies or write test reports Use test seams as temporary
REPORT zmy_copy. workaround
" for playing around They are not a permanent solution!
Assertions
Test publics, not private internals Use LOCAL FRIENDS to access the
CLASS unit_tests DEFINITION LOCAL FRIENDS
dependency-inverting constructor Few, focused assertions
assert_not_initial( itab ).
Don’t obsess about coverage if it’s hidden away assert_equals( act = itab exp = exp ).
60% -> all done!
Don’t misuse LOCAL FRIENDS to invade Use the right assert type
the tested code assert_equals( act = itab exp = exp ).
CLASS unit_tests LOCAL FRIENDS cut. assert_true( itab = exp ).
cut->db_reader = stub_db_reader
Test classes Assert content, not quantity
Don’t change the productive code to assert_contains_message( key )
Call local test classes by their purpose make the code testable assert_equals( act = lines( messages )
CLASS unit_tests exp = 3 ).
IF in_test_mode = abap_true.
CLASS tests_for_the_class_under_test
Assert quality, not content
Don’t sub-class to mock methods
Put tests in local classes assert_all_lines_shorter_than( … )
Use test seams or OSQL_REPLACE or extract the
REPORT some_tests_for_this
methods to own class Use FAIL to check for expected
Don’t mock stuff that’s not needed exceptions
METHOD throws_on_empty_input.
DATA unused_dependency TRY.
Code under test " when
Don’t build test frameworks cut->do_something( '' ).
Name the code under test setup( test_case_id = '4711' ) cl_abap_unit_assert=>fail( ).
CATCH /clean/some_exception.
meaningfully, or default to CUT " then
DATA switch ENDTRY.
DATA cut ENDMETHOD.
Test Methods
Test interfaces, not classes Forward unexpected exceptions
DATA cut TYPE REF TO some_interface Test methods names: reflect what’s
DATA cut TYPE REF TO some_class instead of catching and failing
given and expected METHODS throws RAISING EXCEPTION bad
Extract the call to the code under test METHODS accepts_emtpy_user_input
METHODS test_1 Write custom asserts to shorten code
to its own method
METHODS map_xml_to_itab and avoid duplication
Use given-when-then assert_table_contains( row )
IMPORTING
given_some_data( ). READ TABLE itab
xml_string TYPE string
do_the_good_thing( ). assert_subrc( )
config TYPE … DEFAULT …
assert_that_it_worked( ).
format TYPE … DEFAULT ….

METHOD map_xml_to_itab. “When” is exactly one call


result = cut->map_xml_to_itab( … ). given_some_data( ).
ENDMETHOD. do_the_good_thing( ).
and_another_good_thing( ).
Allows tests to focus on the parameters that are assert_that_it_worked( ).
really needed:
Don’t add a TEARDOWN unless you
METHOD some_test.
map_xml_to_itab( `<xml></xml>` ).
really need it
" recreated in setup anyway
ENDMETHOD.
METHOD teardown.
CLEAR stub_db_reader
ENDMETHOD.

Clean ABAP Cheat Sheet v1.4.1 PUBLIC https://github.com/SAP/clean-abap/blob/master/cheat-sheet/CheatSheet.md

Potrebbero piacerti anche