Skip to content

ilyakaznacheev/abap-best-practice

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

52 Commits
 
 
 
 
 
 
 
 

Repository files navigation

ABAP Best Practices

A list of common principles of clean ABAP development.

Contributing

Missing something? Something is wrong? Find a typo?

Feel free to create an issue or make a pull request. More information in contributors guide.

Contents

Style and Guidelines

Basic approaches to write clean and pleasant code

Use Pretty-Printer

Setup Pretty-Printer in settings and run it every time you save your code.

Set same Pretty-Printer settings in your project guidelines to avoid different formatting in the same systems.

Use Naming Conventions

Choose naming rules for every code or dictionary object you create. Use it to avoid confusion.

In addition, you can setup Code Inspector to check naming convention.

Use snake_case

Name your variables, methods, classes, etc. with underscores between words like lo_table_container->get_sorted_table_data(). It is the standard convention for ABAP.

Wikipedia

Use consistent spelling

There are many alternative language constructs in ABAP like set of (=, <>, >=, etc.) vs. (EQ, NE, GE, etc.), data declarations, operations, etc.

Choose one of alternatives and use it consistently during your development.

SAP Help

Avoid obsolete statements

Some statements in ABAP are outdated. Some of them are deprecated, some are just replaces with new operands. Try to avoid obsolete statements if there some newer alternative exists.

SAP Help

Coding

Common rules of writing better code in ABAP

Follow the Separation of Concerns principle

Separate program into units with minimal overlapping between the functions of the individual units.

Write self-describing code

Good code should explain itself. Self-describing code doesn't require so much comments or huge documentation.

Make you statements self-explanatory, e.g.:

  • choose meaningful names for variables, functions, classes, etc. (lv_ilv_index, lt_datalt_sale_orders, cl_utilcl_file_io_helper, start()run_accounting_document_processing())
  • group logical steps into methods (e.g. split method process_document() into sequence of methods prepare_document_data(), is_doc_creation_possible(), lock_tables(), create_document(), unlock_table(), etc.)
  • decrease amount of lines in a programming block
  • decrease nesting level
  • avoid implicitness

Comment what you do, not how you do

Do not comment aspects of implementation, a self-describing code will provide this information for a reader. Comment logic from the business process point of view, the information that the reader can't extract from code.

In the best case, short description of business logic unit in method header or before method call will be enough.

Be as local as possible

Create variables, methods and attributes with as lowest scope as possible. The greater the scope you variable/method has, the more coupled your program is.

Do not use magic numbers

Avoid hard-coded constants or unnamed variables.

Instead, move them into meaningful variables or constants. Note, that just move text literal with the same name is not enough (ABC123lc_abc123), give it a proper description (ABC123lc_storage_class)

Bad:

lo_doc_processor->change_document(
  iv_blart = 'AB'
  iv_bukrs = 'C123'
  iv_popup = lv_x
).

Good:

CONSTANTS:
  lc_clearing_document TYPE blart VALUE 'AB',
  lc_main_company      TYPE bukrs VALUE 'C123'.
DATA:
  lv_show_popup TYPE abap_bool.
*...
lo_doc_processor->change_document(
  iv_blart = lc_clearing_document
  iv_bukrs = lc_main_company
  iv_popup = lv_show_popup
).

SAP Help

Avoid deep nesting

Don't write deeply nested loops, cases, and other control structures. Instead of nesting exit from control structure with ifs, checks, and returns.

Bad:

LOOP AT lt_data ASSIGNING <ls_data>.
  IF a = b.
    IF c = d.
      IF ls_data IS NOT INITIAL.
        ls_data-field = 'aaa'.
      ENDIF.
    ELSE.
      ls_data-field = 'bbb'.
    ENDIF.
  ELSE.
    ls_data-field = 'ccc'.
  ENDIF.
ENDLOOP.

Good:

LOOP AT lt_data ASSIGNING <ls_data>.
  IF a <> b.
    ls_data-field = 'ccc'.
    CONTINUE.
  ENDIF.

  IF c <> d.
    ls_data-field = 'bbb'.
    CONTINUE.
  ENDIF.

  CHECK ls_data IS NOT INITIAL.
  ls_data-field = 'aaa'.
ENDLOOP.

SAP Help

Use automated code checks

Use syntax check, extended program check, and code inspector to validate your code syntax, architecture, guidelines, vulnerabilities, and other quality aspects.

Open Source list of checks for SCI/ATC

Delete dead code

Remove old and unused code. Syntax check and extended program check will help you to find it.

SAP Help

Do not ignore errors

React to errors. It can be either a proper message, or a blog entry, or an exception raising. But don't ignore them, otherwise, you will no way to find a cause of any problem.

SAP Help

Use class-based exceptions

There are several historical types of error in ABAP - system exceptions, classic exceptions, and class-based exceptions. System exceptions aren't allowed to use, classic exceptions are explicit and outdated. There is no reason to use other than class-based exceptions.

SAP Help

Handle exceptions as soon as possible

Better to handle exception closer on call stack to the raising clause. Handle it when the context of current stack level has enough information for proper handling.

One exception class per one problem, several texts for different problem reasons

Don't create many different classes for each raising clause. Instead create one class for one kind of problem, i.e. for one type of problem handling.

Create meaningful messages that describe each reason for this kind of problem. Error handling can be the same, but reasons, logging, and user notification will differ.

Example: you are reading a file from PC. There can be a different problem - file is corrupted, the file is empty, access denied, etc. But if you just want to know, if the file was uploaded successful, one exception class zcl_io_error will be enough. But create proper messages for each error reason or error type to let the user know, why exactly the file was not uploaded.

Check program accessibility

Ensure that your application is can be used by people with impairments. It means that any information on the user interface should be given in an accessible form:

  • input and output fields must have meaningful labels;
  • icons must have a tooltip;
  • table columns must have a header;
  • information must not be expressed by color alone;
  • input and output fields on the screen should be grouped as appropriate in frames, each with a meaningful title.

That ensures, that people with impairments like color blindness or screen-reader users will have full access to application functionality.

SAP Help

Wrap any shared data access into data access classes

When you use some shared data like shared memory, shared objects, buffers, etc., don't access them directly. Instead, wrap them into setter and getter methods of static data access class.

It will help you to control access to shared data and easily find any shared data changes via the where-used list. It will also allow you to mock shared data access in unit tests.

Avoid implicit data declarations

When possible try to not use data declarations like TABLES, NODES. They create data objects with implicit access.

Use DATA instead. Only use NODES with LDB. Both create global work areas that will be shared and used through all the program.

Never use TABLE ... WITH HEADER LINE. Use either structure, field-symbol or reference with the type of table line or inline declarations and table expressions.

SAP Help

Use built-in Boolean types and constants

When you want to use some logical information, use built-in Boolean type abap_bool instead of char1 or other types.

Use constants abap_true and abap_false for Boolean true and false values. Do not use literals like 'X', ' ' - it is a hardcode.

Usage of space, IS INITIAL or IS NOT INITIAL is also not advisable, because they check state of technical implementation of abap_bool, but not the sense of real Boolean data object.

SAP Help

Do not use system fields in UI

System fields (sy) are technical. They should not be shown to the user.

SAP Help

Use a suitable category of internal table

Select a suitable table category. For small tables indexes or hashed keys may be redundant, but for large tables always use the following rule:

  • index accesses: standard table
  • index accesses and key accesses: sorted table
  • only key accesses: hashed tables

SAP Help

Choose an appropriate way to access a table row

There are three ways to store an accessed row of an internal table while reading - INTO copies row into structure, ASSIGNING assigns the row to field symbol and REFERENCE INTO creates a reference to the row. The same is for table expressions, but a row storage type being chosen by the category of the result.

The rule is:

  • use a work area (structure) if the row type is narrow and the read row is not to be modified.
  • use field symbol if the row type is wide or deep and the read row is to be modified.
  • use reference if the row type is wide or deep and a reference to the read row is to be passed.

In performance reason better to avoid row copying in loops.

SAP Help

Do not modify an entire table in a loop

While looping through an internal table, don't execute statements that will modify the entire table body. Only modify table row-by-row.

SAP Help

Exit processing with RETURN

Use only RETURN to exit method, function, form, etc. Do not use CHECK or EXIT.

SAP Help

Do not implement logic in dialog modules and event blocks

Instead, call the relevant class method, that encapsulates logic implementation.

SAP Help

Only use macros in exceptional cases

Avoid macros usage when possible. Macro has several disadvantages:

  • it's unable to debug;
  • no syntax check;
  • implicit call interface
  • no interface parameters type check.

SAP Help

Make anchors for implicitly called messages

When you pass message attributes (class, number, arguments) implicitly, e.g. by function or method call, or using variables, use anchors to let the message be searchable within a where-used list.

It can be done the following way (as it is done in a standard):

IF 1 = 2. MESSAGE i123(abc) ... . ENDIF.

or

MESSAGE i123(abc) ... INTO sy-msgli. "and then use sy-msg* fields to pass the message attributes

Language and Translation

How to make application ready for internationalization and localization

Do not hardcode texts

Never write texts as inline text literals - they are difficult to find and not possible to translate. Use message class or text symbol instead.

Do not use text constants

Do not use constants for storing text (unless it is not text but a char constant). Text constants cannot be translated. Use message class or text symbol instead.

Use text tables for text storage in DB

Do not store texts in same dictionary tables as other data. Create text tables and assign them to the main table via a foreign key. There are some advantages of text tables:

  • They support translation;
  • Several texts can be handled for the same object (e.g. short, medium, long text, etc.);
  • No search help needed. Texts from the text table will be automatically added into a value list;
  • No extra maintaining needed. Text column will be automatically added to a maintenance view;
  • Translations can be done with transaction SE63.

Use same original language for all objects in a project

Pick one language and use it as an origin when you create new objects. It will be easier to maintain and translate in future.

SAP Help

Keep translation in mind

Remember that all texts, messages, names, etc. can be translated. Phrases will have a different length (or even different justification) in different languages. Leave some free space for it.

English phrases are much shorter, than other most-used languages.

Use only English naming for development objects

When you name some programming objects like variables, methods or class names, or dictionary objects like types, structures, tables, etc. use only English names.

Do not use other languages, do not combine them. English is understandable in most countries, it is useful and polite to make your code international. Maybe it will be supported by another team from another country.

And it is just a standard and a best practice in a programming world. Don't be a barbarian.

Use only translatable texts in UI

Send to user only translatable texts, like messages, OTR, text symbols, etc.

SAP Help

Use numbered placeholders in messages

Use numbered placeholders &1 - &4 instead of anonymous placeholders &. Order of inserted words may differ in different languages. A translator may need to change the order of the replacement texts when translating message texts. With anonymous placeholders, it isn't possible.

SAP Help

Object-Oriented Programming

Here are some OOP best practices, not only SAP-specific but also common practices

Use classes instead of functional modules or performs whereas possible

SAP postulates that usage of non-object-oriented code modules is obsolete. Use FMs only where are no possibility to use classes (e.g. RFC, update modules, etc.)

ABAP is an enterprise programming language, and OOP can better then others describe complicated business processes.

Furthermore, all new SAP technologies are class-based.

SAP Help

Stay SOLID

Use SOLID principles in OOP development. Here is five core principles of a flexible and extendable software development:

Use GRASP

This is a set of patterns and principles for assigning responsibility to classes and objects in the object-oriented design.

There are not only useful behavioral patterns but also very important principles like "low coupling" and "high cohesion".

Wikipedia

Learn OOP design patterns

There is a set of well-known classic OOP design patterns, which are very handy in enterprise development. If you know them, you can easily share design ideas with the team, faster solve architecture challenges and find better problem solutions.

Respect The Law of Demeter

  • each unit should have only limited knowledge about other units: only units "closely" related to the current unit;
  • each unit should only talk to its friends; don't talk to strangers;
  • only talk to your immediate friends.

That means if class A has access to class B, and B, in turn, has access to class C, class A shouldn't be able to call a method of C directly like A->B->C->method_of_C(). B has to have a special method for it.

For example if we want a dog to bark, we will not call lc_dog->get_head()->get_voice_functions()->run_bark_sound(), but lc_dog->bark().

Wikipedia

Avoid classes for helpers, utilities, etc.

There are many cases in ABAP development when some utility method may be needed. But instead of static methods turn them into powerful objects. Think about function as a class, that is responsible to do this kind of operations. E.g. instead of utility to upload Excel table into string table, create a class that uploads an Excel table in the constructor and able to give it to you in any shape you want (even as a string table).

You can go ahead and create an interface for table data formatting and implement it for various range of tables - Excel, CSV, XML, etc. Or set a table reader interface as a constructor parameter of table formatter, and implement it for different kinds of data uploads.

In any case, it will be more flexible and more useful as just a static method.

For example:

  • lt_str = cl_file_util=>upload_file_into_str_tab( lv_path )lt_str = NEW cl_file( path )->get_str_tab( )
  • lv_date = cl_format_util=>format_date_to_gmt( sy-datum )lv_date = NEW cl_date_formatter( sy-datum )->get_gmt( )

Database Usage

How to create efficient DB requests

Use OpenSQL whereas possible

Use OpenSQL (ABAP SQL since 7.53) instead of Native SQL. It has several advantages:

  • syntax check;
  • validation check;
  • cross-server interpretation;
  • common syntax;
  • integration with ABAP.

Main causes of NativeSQL usage: performance problems, specific DB functions.

SAP Help

Check sy-subrc after DB operations

Check DB operation status explicitly by checking sy-subrc.

Even if you don't have any error handling, place sy-subrc check to make it explicit and let anyone know, that error handling doesn't require.

IF sy-subrc <> 0. 
  * nothing to do
ENDIF 

SAP Help

Read only those fields you need

Avoid SELECT * in your code. There are several reasons:

  • As many fields you fetch, as more time it takes and as more DB channel capacity it uses. Reading of unnecessary fields is bad from performance reasons;
  • Database table schema may change in the future. If you forget to adapt your program (and you probably will, because table schema may be changed by another person), you will read fields, which aren't needed for your program.

Exception: consumption CDS views, which are unique and designed for a certain use-case, so they probably will consist of necessary fields only.

Check FAE table emptiness

Always check if the table, that you about to use in FOR ALL ENTRIES statement, is not empty.

Otherwise SELECT will return every entry that database table contains ignoring other WHERE conditions.

That is if your database table contains 1K entries and your WHERE clause cuts the number down to 10, if the table in the FAE is empty, select will fetch 1K entries.

Performance

Use this rules to avoid performance bottlenecks

Do not perform SELECT in loops

Try to avoid DB operations in loops like DO-ENDDO, WHILE-ENDWHILE, LOOP-ENDLOOP, PROVIDE-ENDPROVIDE and SELECT-ENDSELECT.

Instead, extract operation criteria from the loop and execute DB operation once.

It may be difficult from an architecture perspective to decouple DB operations from loops. To solve this problem you can use Data Access Class (DAC) pattern to encapsulate all DB operations into some class (or set of classes) and perform DB operations as little as possible (e.g. before loop or after loop using lazy load). Then perform a regular read in a loop, but from internal table encapsulated in DAC, not from DB.

Prefer JOIN over FAE and RANGE

Join operations are much faster because they don't have a lot of inputs (no additional transfer from Application to DB) and field mapping (ON part of your SELECT) is performed using internal DB structures (no additional conversion needed).

Use FAE on HANA

FAE (FOR ALL ENTRIES) is still relevant on HANA. Make sure to update your DB to the latest available patch level and use FDA (Fast Data Access). FDA operations are 10x to 100x times faster than conventional FAE.

2399993 - FAQ: SAP HANA Fast Data Access (FDA)

Reduce the number of DB requests

Try to organize your code in such a way as to execute as little DB requests as possible. DB access often is a bottleneck, and a number of DB sessions is limited. Try to keep performance in mind and group similar requests together.

Fetch 10 rows once instead of 10 requests for each row. It may require to change a program architecture, for example, to calculate request keys before you actually will use the results.

Profile your code

Perform profiling of your code when you write something more complicated, than a list report. Use ST05, SAT or any other profiling tool you need to ensure, that your code has no bottlenecks and performance issues.

Testing

How to check your code quality

Test only public interface

In the unit test, you should not test any internal implementation of the class, e.g. private and protected methods.

Test only public methods, it will simulate the way program uses the class in "real life". Every internal method will be called from public methods anyway. If not - the method doesn't really used in the class and should be removed.

The test should check the behavior of the class, not its implementation. You can refactor or change the implementation, but the test will be the same. If the behavior of the class will not change, no change required in the test too.

Leave any internal logic encapsulated by testing only public methods.

Isolate your tests

Tests should not affect each other. Each test should run separately in isolated environments - e.g. you should clean up the environment before/after a test run.

Keep tests repeatable

Same test input should give the same output, actual values should meet expectations, test behavior should be repeatable.

Use unit tests as behavior example and documentation

A unit test shows how a program module should work. If you will test it the same way, as it is used in a real program, it will be the best documentation (with examples!) for a developer.

Keep tests in mind while designing architecture

Only well-designed programs can be easily tested. To make it easier for unit testing make your modules able to be tested independently. Make them low coupled and highly cohesive, remove unnecessary relations, use dependency injection, hide dependent classes behind interfaces to mock them in tests. SoC, SOLID, GRASP are your friends.

S/4 Programming Model

todo

BOPF

How to use Business Object Processing Framework the right way

Avoid direct access to BOPF data

Do not execute direct DB operations on BOPF tables. BOPF encapsulates different operations, such as buffering, data validations, data calculations, etc. that will be triggered only at BOPF API call. Direct access may cause errors in the BOPF working process.

Core Data Services

How not to get lost in the CDS hierarchy

Avoid business logic in CDS Views

Try to use CDS Views only for data modeling.

If you add some business-related conditions or rules, they will probably require often updates, that can break programs, that use those CDS Views, and unit tests. Changes in CDS Views can also influence overlying CDS Views implicitly.

Use CDS Views as data models only and separate corresponding business logic into ABAP programs or business objects.

Avoid direct access to database tables and table functions in upper layer CDS View hierarchy

For each database table, database view or table function corresponding Basic CDS View should be created. Those views describe meaningful names for database table fields, add associations and data-specific annotations.

For example, a view I_Material for table MARA.

Use Basic Views instead of direct access to database tables in CDS Views. Create Basic CDS View when you create a new database table and want to access its data in CDS.

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •