Вы находитесь на странице: 1из 227

ABAP Development Guidelines

and

SAP Development Naming Conventions

STANDARDS, PRACTICES AND TEMPLATES

The Linc Group

Version 2.0
Quality Approval

Name / Organization Date Signature


(MM/DD/YY)

Author

Reviewed / Approved

Quality Approved

Document History

Version Date Change Description / Reason for Change Prepared by

1.0

1.1

Page: 1 of 227
1.2

2.0

Page: 2 of 227
Document References

Doc-Code Document Title Version / Date Location

Page: 3 of 227
1 General Rules .................................................................................... 9
1.1 Separation of Concern ............................................................................................................. 9
Background ......................................................................................................................... 9
Rule..................................................................................................................................... 9
Details ................................................................................................................................. 9

1.2 KISS Principle ......................................................................................................................... 15


Background ....................................................................................................................... 15
Rule................................................................................................................................... 15
Details ............................................................................................................................... 15

1.3 Correctness and Quality ......................................................................................................... 17


Background .......................................................................................................................
17

2 ABAP-Specific Rules ........................................................................ 20


2.1 ABAP Objects as a Programming Model ............................................................................... 20
Background ....................................................................................................................... 20
Rule................................................................................................................................... 20
Details ............................................................................................................................... 20

2.2 Programm Type and Program Properties .............................................................................. 25


Program Type ................................................................................................................... 26
Program Attributes ............................................................................................................ 29
Original Language ............................................................................................................ 31

2.3 Modern ABAP ......................................................................................................................... 32


Background ....................................................................................................................... 32
Rule................................................................................................................................... 33
Details ............................................................................................................................... 33

2.4 Checks for Correctness .......................................................................................................... 34


Syntax Check .................................................................................................................... 34
Extended Program Check ................................................................................................ 36
Code Inspector ................................................................................................................. 38
ABAP Test Cockpit ........................................................................................................... 40

3 Structure and Style ........................................................................... 42


3.1 Source Code Formatting ........................................................................................................ 42
Uppercase/Lowercase ...................................................................................................... 42

Page: 4 of 227
Statements per Program Line ........................................................................................... 43
Using Pretty Printer........................................................................................................... 45
Line Width ......................................................................................................................... 47

3.2 Naming ................................................................................................................................... 48


Choosing the Language ...................................................................................................
49 Descriptive
Names ............................................................................................................ 49

Names of Repository Objects ........................................................................................... 54


Program-Internal Names .................................................................................................. 56

3.3 Comments .............................................................................................................................. 62


Modification Log and Flower Box ..................................................................................... 62
Choosing the language ..................................................................................................... 63
Content ............................................................................................................................. 64
Arrangement in the Source Code ..................................................................................... 66
3.4 Program and Procedure Structure ......................................................................................... 68
Global Declarations of a Program .................................................................................... 69
Local Declarations ............................................................................................................ 71

3.5 Source Code Organization ..................................................................................................... 73


Source code modularization ............................................................................................. 73
Multiple use of include programs ...................................................................................... 74

3.6 Alternative Spellings ............................................................................................................... 76


Alternative Language Constructs ..................................................................................... 76
Chained Statements ......................................................................................................... 77
Method Calls ..................................................................................................................... 80
Assignments ..................................................................................................................... 82
Calculations ...................................................................................................................... 84

3.7 Complexity .............................................................................................................................. 85


Expressions ...................................................................................................................... 85
Nesting Depth ................................................................................................................... 86
Procedure Volume ............................................................................................................ 87
Class Size ......................................................................................................................... 88
Dead Code ........................................................................................................................ 89

4 Architecture ...................................................................................... 91
4.1 Object-Oriented Programming ............................................................................................... 91

Page: 5 of 227
Encapsulation ................................................................................................................... 91
Modularization .................................................................................................................. 92
Static Classes and Singletons .......................................................................................... 95
Inheritance ........................................................................................................................ 97
Class References and Interface References .................................................................... 98
Local Types for Global Classes ........................................................................................ 99
Instance Constructor....................................................................................................... 100

4.2 Error Handling ...................................................................................................................... 101


Reaction to Error Situations ............................................................................................ 101
Classical and Class-Based Exceptions ..........................................................................
102 Exception Categories......................................................................................................
105
Exception Texts .............................................................................................................. 106
Using Exception Classes ................................................................................................ 108

Handling and Propagating Exceptions ........................................................................... 109


Cleanups After Exceptions ............................................................................................. 110
Assertions ....................................................................................................................... 111
Messages ....................................................................................................................... 112

4.3 User Interfaces ..................................................................................................................... 114


Selecting the User Interface Technology........................................................................ 114
Encapsulating Classical User Interfaces ........................................................................ 116
Lists................................................................................................................................. 119
Accessibility .................................................................................................................... 120

4.4 Data Storage ........................................................................................................................ 121


Persistent Data Storage ................................................................................................. 121
Databases Accesses ...................................................................................................... 122
Client Handling ............................................................................................................... 124
Using Shared Memory .................................................................................................... 125
Using Shared Objects ..................................................................................................... 127

5 Robust ABAP ................................................................................. 129


5.1 Data Types and Data Objects .............................................................................................. 129
Bound and Standalone Data Types ................................................................................ 129
Declaration of Data Types and Constants ...................................................................... 131
Declaration of Variables ................................................................................................. 133

Page: 6 of 227
Inline Declarations .......................................................................................................... 135
Including Structures ........................................................................................................ 136
Using Types .................................................................................................................... 138
Reference to Data Types or Data Objects ..................................................................... 139
Table Work Areas ........................................................................................................... 140
Literals ............................................................................................................................ 141
Strings ............................................................................................................................. 143
Start Values .................................................................................................................... 144

Data Objects for Truth Values ........................................................................................ 145


5.2 Assignments, Calculations and Other Types of Data Access .............................................. 146
Assignments Between Different Types........................................................................... 147
Avoiding Invalid Values .................................................................................................. 148
Using Conversion Rules ................................................................................................. 149
Trailing Blanks in Character Literals ............................................................................... 150
Specifying Numbers........................................................................................................

152 Selecting the Numeric Type ........................................................................................... 153


Rounding Errors .............................................................................................................. 155
Dividing by Zero .............................................................................................................. 156

Casting ............................................................................................................................ 157


Runtime Errors When Accessing Data Objects .............................................................. 159
Anonymous Containers .................................................................................................. 160

Pass by Reference of Global Data ................................................................................. 161


5.3 Systems Fields ..................................................................................................................... 162
Access ............................................................................................................................ 162
Obsolete and internal system fields ................................................................................ 163
Evaluation ....................................................................................................................... 164
Return value ................................................................................................................... 165
Use as current parameter ............................................................................................... 166
Using system fields on the user interface ....................................................................... 167
Use in operand positions ................................................................................................ 168

5.4 Internal Tables ...................................................................................................................... 169


Selecting the Table Category ......................................................................................... 170
Secondary Keys .............................................................................................................. 172
Initial Memory Requirements .......................................................................................... 174

Page: 7 of 227
Sorted Filling ................................................................................................................... 175
Compressed Filling ......................................................................................................... 176
Output Behavior .............................................................................................................. 177
Loop Processing ............................................................................................................. 178

5.5 Modularization units.............................................................................................................. 179


Function Modules and Subroutines ................................................................................ 179
Type of Formal Parameters in Procedures..................................................................... 180
How Formal Parameters Are Passed ............................................................................. 182
Pass By Reference for Output Parameters .................................................................... 183
Typing of Formal Parameters ......................................................................................... 185
Internal and External Procedure Calls ............................................................................ 187
Exiting Procedures .......................................................................................................... 189
Dialog Modules and Event Blocks .................................................................................. 191
Macros ............................................................................................................................ 192

5.6 Dynamic Programming Techniques ..................................................................................... 194


Using Dynamic Programming Techniques ..................................................................... 194
Runtime Errors in Dynamic Processing .......................................................................... 196
Using Dynamic Data Objects .......................................................................................... 197
Memory Consumption of Dynamic Memory Objects ......................................................
198 Administration Costs of Dynamic Memory Objects ........................................................
200
Accessing Data Objects Dynamically ............................................................................. 201
Generic Programming..................................................................................................... 203

5.7 Internationalization ............................................................................................................... 206


Storing System Texts...................................................................................................... 206
Translation-Friendly Message Texts .............................................................................. 207
Text Environment ............................................................................................................ 209
Character Set in Source Code ........................................................................................ 210
Splitting Texts ................................................................................................................. 211
Code Pages for Files ...................................................................................................... 211

6 Security .......................................................................................... 213


6.1 Security Principles ................................................................................................................ 213
Document implicit security assumptions......................................................................... 213
Follow the principle defense in depth ............................................................................. 213
Do not trust the client - there is no client-side security ................................................... 213

Page: 8 of 227
Write your code with an attacker's mindset .................................................................... 213
Do not write your own cryptographic functions ............................................................... 214

6.2 Secure Programming............................................................................................................ 214


Input Validation ............................................................................................................... 214
Output Encoding ............................................................................................................. 216
Access management OWASP: A7 - Broken Authentication and Session Management216
Information management WASC: 5.2 Information Leakage ........................................... 217

6.3 Avoiding common vulnerabilities .......................................................................................... 217


SQL Injection OWASP: A2 - Injection Flaws WASC: 4.5 SQL Injection ....................... 217
Directory Traversal OWASP: A4 - Insecure Direct Object Reference WASC: 5.3 Path
Traversal ....................................................................................................................................... 218
Command Injection OWASP: A2 - Injection Flaws WASC: 4.4 OS Commanding ......... 219

7 Modification and Enhancements ..................................................... 221


7.1 Coding in any Standard Object ............................................................................................ 221
7.2 Soft (Hard) Coding................................................................................................................ 223

1 GENERAL RULES
The following rules do not apply specifically to ABAP, even if they are demonstrated here in the context of
ABAP programming, but apply equally well to all types of business application programming. Many of the
rules described in this section are either derived from the general rules or support these rules.

1.1 Separation of Concern


Background
The term 'separation of concerns' (SoC) was coined in Edsger W. Dijkstra's article On the role of scientific
thought from 1974:
"... But nothing is gained --on the contrary!-- by tackling these various aspects simultaneously. It is what I
sometimes have called 'the separation of concerns', which, even if not perfectly possible, is yet the only
available technique for effective ordering of one's thoughts, that I know of. This is what I mean by
'focusing one's attention upon some aspect': it does not mean ignoring the other aspects, it is just doing
justice to the fact that from this aspect's point of view, the other is irrelevant." (Springer-Verlag, 1982)
Separation of concerns is a principle used in programming to separate an application into units, with
minimal overlapping between the functions of the individual units. The separation of concerns is achieved
using modularization, encapsulation and arrangement in software layers.
Although the classic three-layer architecture of the SAP system - now named SAP NetWeaver Application
Server ABAP (AS ABAP) - is ideal for ABAP programming based on the SoC principle, this possibility was
never explored. Application programs (in other words, dialog programs in module pools or reports in
executable programs) were usually displayed as monolithic blocks, in which the system simultaneously
reacted to user actions of the presentation layer, completed the application logic and executed accesses
to data on the persistency layer. This type of programming is no longer relevant in today's programming
word, where concepts like service-oriented architecture (SOA) set the trend.

Page: 9 of 227
Rule
Follow the SoC principle
Follow the separation of concerns principle. Model your applications strictly as service-oriented
applications. It is especially important that you separate the logic of the application layer from the logic of
the presentation layer, the persistency layer and the logic for communication with external systems.
Encapsulate the repository objects of the individual concerns in separate packages.

Details
The SoC principle identifies the parts of an application with a specific purpose and encapsulates these
parts in closed units. These units only communicate with each other using specified interfaces. Thanks to
this principle, the software - which would have otherwise been overcomplicated - is divided up into
manageable components. As a result, the software is:
• more stable
• easier to understand
• easier to reuse
• easier to transport
• easier to maintain
• easier to test
Regarding the last point, it would even be true to say that following the SoC principle is a prerequisite for
executing isolated, automated unit tests.

1.1.3.1 Bad example


The following graphic shows two examples of an ABAP application that do not follow the SoC principle.

In fact, the two bad examples here are the programmer models for reporting and dialog programming that
were propagated by SAP for a considerable length of time! To be more precise, the example is not bad
due to the reporting or programming of transactions itself, but due to the way in which these applications
are usually implemented. The mini report in the following source code is a typical example of how different

Page: 10 of 227
concerns are mixed together in a single program unit. Both the data declarations and the implementation
of the functions are mixed together. Access to persistent data, data processing, data presentation and the
associated declarations all occur in one single unit.
REPORT z_non_soc_report.
PARAMETERS p_carrid TYPE spfli-carrid.
DATA: spfli_tab TYPE STANDARD TABLE OF spfli
alv TYPE REF TO cl_salv_table,
alv_exc TYPE REF TO cx_salv_msg.
SELECT *
FROM spfli
WHERE carrid = @p_carrid
INTO TABLE @spfli_tab.
IF sy-subrc = 0.
SORT spfli_tab BY cityfrom cityto.
TRY.
cl_salv_table=>factory(
IMPORTING r_salv_table = alv
CHANGING t_table = spfli_tab ). alv-
>display( ).
CATCH cx_salv_msg INTO alv_exc.
MESSAGE alv_exc TYPE 'I' DISPLAY LIKE 'E'.
ENDTRY. ENDIF.
Of course, it would be too much to insist that concerns should be completely separated even in short
programs like in the source code above. However, real applications are usually very long ABAP programs
(executable programs, module pools), in which all concerns are handled at the same time. If
modularization was performed, it was usually restricted to reusing functional units and was rarely focused
on the actual available layers. In addition, large volumes of global data were usually created that were
used in different procedures and layers. As a result, all the parts of the program were inherently
dependent on each other and could not be tested individually. We are convinced that the quality of these
programs can be improved not only by following naming conventions, but also by changing the paradigm
for the procedure used for programming tasks.
The following source codes proves that you can implement the SoC principle using classic ABAP
procedural methods (in this case, subroutines). This source code has the same functionality as the source
code above. However, all the concerns are implemented in separate procedures that are assigned to
layers. As we have already mentioned, this type of implementation would be too much for a simple
program. However, if you needed to test the concerns in the above source code individually and
independently of each other by using unit tests, the only possibility would be to adapt the source code as
shown below. The program of the following source code can now be easily assigned test methods in
ABAP unit test classes, which test the individual procedures.
REPORT z_soc_report.
SELECTION-SCREEN BEGIN OF SCREEN 100.
PARAMETERS p_carrid TYPE spfli-carrid.
SELECTION-SCREEN END OF SCREEN 100.
TYPES spfli_tab TYPE STANDARD TABLE OF spfli.
DATA: carrid TYPE spfli-carrid,
table TYPE spfli_tab, arc
TYPE sy-subrc.
START-OF-SELECTION.
PERFORM get_carrid CHANGING carrid.
PERFORM get_table USING
carrid CHANGING table
arc.
IF arc = 0
PERFORM sort_table CHANGING table.

Page: 11 of 227
PERFORM display_table USING table.
ENDIF.
* Presentation layer
FORM get_carrid
CHANGING value(carrid) TYPE spfli-carrid.
CALL SELECTION-SCREEN 100.
IF sy-subrc = 0.
carrid = p_carrid.
ENDIF.
ENDFORM.
FORM display_table
USING table TYPE spfli_tab.
DATA: alv TYPE REF TO cl_salv_table,
alv_exc TYPE REF TO cx_salv_msg.
TRY.

cl_salv_table=>factory( IMPORTIN
G r_salv_table = alv CHANGING
t_table = table ).
alv->display( ).
CATCH cx_salv_msg INTO alv_exc.
MESSAGE alv_exc TYPE 'I' DISPLAY LIKE 'E'.
ENDTRY.
ENDFORM.
* Application layer
FORM sort_table
CHANGING table TYPE spfli_tab.
SORT table BY cityfrom cityto.
ENDFORM.
* Persistency layer
FORM get_table
USING carrid TYPE spfli-carrid
CHANGING table TYPE spfli_tab
arc TYPE sy-subrc.
SELECT *
FROM spfli
WHERE carrid =
@carrid INTO TABLE
@table. arc = sy-subrc.
ENDFORM.
However, this separation of concerns using subroutines shown above does not create a good
impression. The following source code shows how the separation of concerns should be implemented
instead using methods in concern-specific classes.

1.1.3.2 Good example


The following graphic shows how an ABAP application should look that follows the separation of concerns.

Page: 12 of 227
After the concerns have been identified, they are implemented in ABAP object classes. The concerns
shown in the graphic are the main tasks that are usually performed in ABAP application programming:
Communication with a user interface (UI) using UI services
Actual application logic
Access to persistent data using persistency services

Communication with external systems using proxy services


These main rules can be subdivided further, which is often necessary.
The boxes for the individual concerns in the graphic represent packages. All the repository objects
(classes, data types) belonging to a concern should be located in corresponding packages. The package
concept (encapsulated packages) supports this separation of concerns. In encapsulated packages,
repository objects in one package can only access the objects of another package using package
interfaces, which is checked by the syntax check. A package can restrict the usability of its repository
objects even more by using access control lists. Subdividing the separation of concerns in a package is a
concept supported by subpackages.
For example, encapsulating all database tables of an application in a package for persistency services
prevents any program, that does not belong to this package, from accessing these database tables. The
reverse is also true. For example, programs in the persistency layer cannot communicate directly with
components in the presentation layer, such as a Web Dynpro ABAP application. You should prepare the
package encapsulation (by choosing Package Check as Server) in the package properties. These
packages have package interfaces, A package check is performed during the extended program check.
The following source code shows how to adapt the separation of concerns from the above source code for
classes local to the program.
REPORT z_soc_class_report.
SELECTION-SCREEN BEGIN OF SCREEN 100.
PARAMETERS p_carrid TYPE spfli-carrid.
SELECTION-SCREEN END OF SCREEN 100.

Page: 13 of 227
TYPES spfli_tab TYPE STANDARD TABLE OF spfli.
CLASS presentation_server DEFINITION.
PUBLIC SECTION.
CLASS-METHODS:
get_carrid RETURNING VALUE(carrid) TYPE spfli-carrid,
display_table IMPORTING VALUE(table) TYPE spfli_tab. ENDCLASS.
CLASS presentation_server IMPLEMENTATION.
METHOD get_carrid.
CALL SELECTION-SCREEN 100.
IF sy-subrc = 0.
carrid = p_carrid.
ENDIF.
ENDMETHOD.
METHOD display_table.
DATA: alv TYPE REF TO cl_salv_table,
alv_exc TYPE REF TO cx_salv_msg.
TRY.

cl_salv_table=>factory( IMPORTIN
G r_salv_table = alv CHANGING
t_table = table ).
alv->display( ).
CATCH cx_salv_msg INTO alv_exc.
MESSAGE alv_exc TYPE 'I' DISPLAY LIKE 'E'.
ENDTRY.
ENDMETHOD.
ENDCLASS.
CLASS application_server DEFINITION.
PUBLIC SECTION. CLASS-
METHODS
sort_table CHANGING table TYPE spfli_tab.
ENDCLASS.
CLASS application_server IMPLEMENTATION.
METHOD sort_table.
SORT table BY cityfrom cityto.
ENDMETHOD.
ENDCLASS.
CLASS persistency_server DEFINITION.
PUBLIC SECTION. CLASS-
METHODS
get_table IMPORTING carrid TYPE spfli-
carrid EXPORTING table TYPE
spfli_tab arc TYPE sy-subrc.
ENDCLASS.
CLASS persistency_server IMPLEMENTATION.
METHOD get_table.
SELECT *
FROM spfli
WHERE carrid = @carrid
INTO TABLE @table.
arc = sy-subrc.
ENDMETHOD.
ENDCLASS.
CLASS report DEFINITION.
PUBLIC SECTION.

Page: 14 of 227
CLASS-METHODS main.
ENDCLASS.
CLASS report IMPLEMENTATION.
METHOD main.
DATA: carrid TYPE spfli-carrid,
table TYPE spfli_tab, arc
TYPE sy-subrc.
carrid = presentation_server=>get_carrid( ).
persistency_server=>get_table( EXPORTING carrid = carrid
IMPORTING table = table
arc = arc ).
IF arc = 0.

application_server=>sort_table( CHANGIN
G table = table ).
presentation_server=>display_table( table ).
ENDIF.
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION. report=>main(
).
At first glance, the above source code appears to be very excessive compared to the first source code.
But only on the first glance. A real application program usually only consists of 25 lines. The larger and
more realistic the application program, the smaller the proportion of the overhead that is generated from
wrapping the concerns in classes. If the reuse options for ABAP Objects are used appropriately, it is even
possible to reduce the amount of source code.
In addition, the individual steps are now wrapped in classes, in other words, real program units (unlike in
the second source code). In practice, wrapping is not performed in one single program, but in global
classes that are assigned to different packages, depending on the layer. These packages are connected
to each other using package interfaces. It is only by using these interfaces that you can achieve the other
benefits of separating the concerns (in addition to the testing capability achieved in the second source
code).

1.2 KISS Principle


Background
The KISS principle says that you should always choose the simplest solution for a problem. KISS is an
acronym and can have any of the following meanings (the list is not exhaustive):

• Keep it simple, stupid.

• Keep it small and simple.

• Keep it sweet and simple.

• Keep it simple and straightforward.

• Keep it short and simple.

• Keep it simple and smart.

• Keep it strictly simple.

Page: 15 of 227
The basic statement of the KISS principle is similar to Occam’s razor, which says that in science the
preferred theory is the one that makes fewest assumptions to explain observations (see Wikipedia entry
on the KISS principle).

Rule
Follow the KISS principle

Follow the KISS principle, and limit the complexity of your programs as far as possible.

Details
The best solution to a problem is usually the one that is as simple, minimalist, and easy to understand as
possible, while ensuring stability, understandability, and maintainability in addition to functional
correctness.

There are plenty of bad examples of the KISS principle. Why is this?

• Programs are too complex right from the start. This can be due to poor design or simply a rash,
undisciplined programming style.

• Programs are maintained for lengthy periods. Instead of creating new implementations for old
and new functions together, new functions are simply added (usually using IF control structures)
to old functions. Programs that were initially simple thus become ever more complex, although
this is not justified by the complexity of the task at hand.

To develop according to the KISS principle, you should ensure right from the start that the complexity of
the program remains manageable. Rules that support this approach relate to the structure and style of
programs, in particular comments and complexity.

1.2.3.1.1 Note

If existing programs do not follow the KISS principle, and these programs need to be further developed,
we recommend refactoring as appropriate. Refactoring refers to the process of manually or automatically
improving the structure of programs while retaining the observable program behavior. It improves legibility,
understandability, maintainability, and extensibility, as well as considerably reducing the related effort for
troubleshooting and functional enhancements (see Wikipedia entry on refactoring). The (incremental)
refactoring of an existing program is not only useful for following the above rule, but also for all following
rules.

The refactoring of existing code is supported by the required coverage by unit tests. Comprehensive unit
tests can ensure that a program behaves in the same way after the refactoring process.

1.2.3.1.2 Example

The figure below shows the structure of a method that does not follow the KISS principle. The method
consists of approximately 160 statements and reaches a nesting depth of 12 levels. The method, which is
only illustrated schematically, is a real example from a live ABAP program, which reached the state shown
on the left after continuous additional developments. The method had become so complex that it was
practically impossible to make another necessary change, and the developer was forced to refactor in line
with the KISS principle.

Page: 16 of 227
The result is illustrated on the right of the figure. By splitting the method M into three methods, each with
less than 100 statements and a maximum nesting depth of 5 levels, manageable modularization units
were generated, which follow the rules for complexity, and allow the required modification to be made.
Ideally, however, the state shown on the left side of the figure should never occur.

1.3 Correctness and Quality


Background
Most organizations that develop professional software have product standards that must be adhered to.
These product standards define what is meant by correctness and quality of a program. SAP has many
such standards, which development departments have to comply with. The current product standards that
are most important to developers are listed below:

• Accessibility
In the information technology environment, the term accessibility relates to the requirement that
anyone, including and especially those with impairments, can access and use information
technology products. To make products such as software or websites accessible to all users, they
must be created and designed so that they can still be used if users have a particular impairment
(for example, visual impairment, color blindness) and must be compatible with technologies such
as screen readers and screen magnifiers.

• Documentation

Page: 17 of 227
As a rule, a product standard for documentation defines which documents have to be shipped to
the consumer with the product and ensures that the documentation supplied is consistent,
correct, and up to date across all product areas.

• Functional correctness
The functional correctness of software is generally seen as its most important quality. Software
that is not functionally correct is usually unusable. As a rule, a product standard for functional
correctness requires software to be error-free, and defines the stability of interfaces and program
behavior during upgrades. To reach these goals, thorough testing of the software may be made
compulsory.

• Globalization
If software is to be used worldwide, a product standard for globalization is usually necessary. This
covers the aspects of internationalization and localization.

o Internationalization
Internationalization comprises the technical aspects of globalization such as Unicode
compatibility, text processing, screen display, printing, data exchange, time zones,
translatability, and so on, and thus sets out the technical prerequisites for localization. The
translation of user interfaces and other texts is also, of course, an important aspect of
internationalization.

o Localization
Localization is necessary if software for global use has to be adapted to local (usually
countryspecific) conditions, such as legal requirements or particular business procedures.

• Performance
Even if a program is functionally correct, it is of little or no use to a user if it cannot be executed in
a reasonable time. A performance product standard ensures that this aspect is not neglected. It
can include, for example, rules for efficient database access and scalability of application logic.

• Security
Where security is critical to software, and this is generally the case for any type of business
software, a product standard for security sets out all security-relevant aspects of a product, by
pointing out any potential security gaps or legal requirements, for example, and also contains
instructions for meeting the standard.

• Usability
The term usability refers to the adaptation of user interfaces to the requirements of human end
users and their tasks. A usability product standard should ensure that end users can perform their
tasks efficiently and effectively. Key aspects of usability include consistency of user interfaces,
ease of use, intuitive task- and role-specific interfaces, individual adaptability, error tolerance, and
so on.

Although these standards are, in part, legal requirements, they essentially arise from the fundamental aim
to guarantee the correctness and quality of the software that is shipped to consumers. Programming
guidelines are very important in this respect. Many of the guidelines listed here support, directly or
indirectly, one of the standards mentioned or are derived from them. They support and ensure compliance
with such standards, resulting in correct, high-quality programs. The programming guidelines themselves
could even be said to be on a par with binding product standards.

However, since not all possible product standards can be covered by the programming guidelines, for
example all rules of a performance or security standard, we set out the following basic rule.

Page: 18 of 227
1.3.1.1 Rule

Comply with or check compliance with existing product standards

Adhere to the product standards that exist in your organization, and ensure the correctness and quality of
your programs by testing them during development and after completion with all the test tools at your
disposal.

1.3.1.2 Details

It is obvious that you must comply with product standards; this needs no further explanation. However, it is
often forgotten that the static and dynamic analysis tools that are available in the ABAP environment can
provide invaluable help for compliance with important product standards, particularly standards for
functional correctness and performance. Therefore, as part of this basic rule we recommend that you use
all available tools that help to ensure the correctness and quality of ABAP programs.

• Run Code-Profiler (transaction /VFORGE/CP) on a regular basis and correct all findings

• Perform the extended program check (transaction SLIN) on a regular basis and correct all
messages.

• Use the Code Inspector tool (transaction SCI) on a regular basis using the standard check variant,
and correct all messages.

• Check the usability and accessibility of your interface elements by using the appropriate tools
(integrated into the workbench tools and ABAP Test Cockpit).

• Cover all functions of your procedural units by using units tests with ABAP Unit (integrated into
ABAP Workbench, Code Inspector, and ABAP Test Cockpit).

• Cover all functions of your applications by using scenario tests with eCATT (transaction SECATT).

• Check the memory consumption of your programs by using ABAP Memory Inspector (transaction
S_MEMORY_INSPECTOR and the memory analysis function integrated into ABAP Debugger).

• Check runtime behavior and performance by using the ABAP runtime analysis tool (transaction
SAT).

• Check the test coverage by using Coverage Analyzer (transaction SCOV and integrated into
ABAP Unit Browser of ABAP Workbench).

• Follow the ABAP - Security Notes to protect your programs and data from attacks from outside.

• Document your programs and services using all available means: Starting with comments, this
ranges from simple data element documentation for context-sensitive input help, to class and
method documentation for documenting APIs, to explanations of concepts and tutorials in other
repositories such as SAP Knowledge Warehouse, or on the Internet, for example in the SAP
Developer Community (SCN, http://scn.sap.com).

1.3.1.2.1 Note

Page: 19 of 227
Where in doubt, product standards take precedence over the guidelines and recommendations of this
documentation. If, for example, performance or security aspects prohibit any of the programming practices
presented here, compliance with the standard takes priority.

1.3.1.2.2 Good example

Executing unit tests for classes of the package SABAP_DEMOS_CAR_RENTAL_APPL and displaying the
results in ABAP Unit Browser of Object Navigator gives a test coverage of 100%. This package is shipped
as a subpackage for the application layer of a small example application, which, in addition to unit tests,
also demonstrates strict adherence to the separation of concerns.

Page: 20 of 227
2 ABAP-SPECIFIC RULES
2.1 ABAP Objects as a Programming Model
Background
ABAP is a hybrid programming language that supports both a procedural and an object-oriented
programming model. The procedural programming model is based on the modularization of programs in
classical processing blocks (event blocks, dialog modules, function modules and subroutines). In ABAP
Objects, the class conceptually supersedes the classical program, and modularization is implemented
using methods. From a technical point of view, classes are still declared and implemented in programs.

Both models possess interoperability, meaning that classes can be accessed in classical processing
blocks and classical programs and procedures can be called within methods. The hybrid nature of the
language is mainly due to the downward compatibility. This is because ABAP has procedural roots, and
the introduction of the object-oriented programming model was intended to make sure entire programs
and reusable procedures (primarily function modules) could still be used.

Rule
Use ABAP objects

Use ABAP objects wherever possible for new and further developments. Classical processing blocks
should only be created in exceptional cases.

Details
The need to achieve separation of concerns is best supported by using ABAP objects as much as
possible. Object-oriented programming - particularly ABAP Objects in comparison to classical procedural
ABAP - is better suited. Here are the reasons why:

1. Data encapsulation
ABAP Objects enables an advanced type of data encapsulation to be used. In classical
procedural programming, the state of an application is determined by the content of the global
variables of a program. In object-oriented programming, the state is encapsulated in classes or
objects as instances of classes. The distribution of data across the different visibility sections of a
class — public, protected and private — allows a clear differentiation between externally and
internally usable data. Even without in-depth object-oriented modeling, application programs
benefit from these properties in terms of stability and maintainability.
2. Explicit instantiation
ABAP Objects enables multiple instantiation of a class, by using explicit object creation with the
CREATE OBJECT statement. Each instance of a class (object) has its own state that is
determined using the values of its attributes. It can be changed using class methods. Automatic
garbage collection ensures that any objects no longer required are deleted from the memory.
Procedural models do not offer multiple instantiation. Therefore stateless functions must be
applied to data stored in separate repositories.
3. Inheritance
ABAP Objects enables the reuse of classes through inheritance, where classes with special
behaviors are derived from more general classes. Only the differences must be implemented
again. In the procedural model, only existing functions can be used as they are, or new functions
must be created.

Page: 21 of 227
4. Interfaces
In ABAP Objects, objects can be addressed using standalone interfaces. This means that
developers do not need to concern themselves with the implementation details of the class
behind the interface. The provider of an interface can change the underlying implementations,
without having to modify the programs that the interface uses. The procedural model does not
have this concept of standalone interfaces.
5. Events
ABAP Objects makes it easier to implement event-driven program flows. A publish-and-subscribe
mechanism can loosely couple applications. The event trigger does not need to know anything
about any possible handlers. This allows greater flexibility than the procedural approach, where
the programs are much stronger coupled and the program flow is usually much more strictly
defined.
6. Explicit orthogonal concepts
ABAP Objects contains a small number of closely defined, mutually orthogonal, fundamental
concepts, which makes it more reliable and less error-prone than classical ABAP. Classical
procedural ABAP is dominated by implicit behaviors, where programs are controlled by implicit
events of the runtime environment and by global data. The concepts of ABAP Objects, however,
are explicitly shown in a program. ABAP Objects is easier to learn and use than classical
procedural ABAP.
7. Cleansed syntax
ABAP Objects uses cleansed syntax rules and semantics rules. Classical procedural ABAP is a
language that has evolved over time, and contains several obsolete and overlapping concepts.
The introduction of ABAP Objects meant that classes and methods provided a field for cleansed
syntax and semantics rules, which was completely unaffected by downward compatibility
requirements. This meant that most obsolete and error-prone language constructs were
syntactically forbidden in ABAP Objects (within classes and methods). Also, any questionable and
potentially incorrect data accesses are checked more closely and can also be forbidden. The
syntax cleansing enforces the
use of the ABAP language in classes, which can only be requested using the Modern
ABAP guideline, outside of classes.
8. Access to new technologies
ABAP Objects is often the only way of dealing with new ABAP technologies. For example, GUI
controls, Web Dynpro ABAP, runtime type services (RTTS), orInternet Connection Framework
(ICF) only provide class-based interfaces. If programs that use these services were still
implemented on a purely procedural basis, this would result in an unnecessary mix of
programming models and increased complexity.

Therefore the urgent recommendation to use ABAP Objects has both formal and content-related issues:

• As described in points 1 through 5, the object-oriented programming model is better suited to


keeping the complexity of software manageable through principles, such as encapsulation and
inheritance. Admittedly, a good object-oriented design is not an easy task, and there are
developers with only limited experience in this area even today. Given these facts, anyone who is
still considering approaching a new development in the classical procedural way, must bear in
mind that the procedural event-driven ABAP programming model with its system events is also
not easy to understand.

• Points 6 through 8 describe more formal aspects. These points suggest that procedures should
be created only as methods, even in the absence of a real object-oriented design. Function
modules and subroutines should be created only in exceptional cases, where ABAP Objects does
not currently provide any alternatives.

The section Object-Oriented Programming provides notes and recommendations on the optimal use of
ABAP Objects.

Page: 22 of 227
2.1.3.1 Exception

The following properties are still missing in ABAP Objects. They are needed to replace classical
processing blocks with methods:

• Remote Method Invocation (RMI) as a replacement for Remote Function Call (RFC)

• A replacement for the call of update function modules (CALL FUNCTION IN UPDATE TASK)

• A replacement for the call of subroutines during COMMIT WORK and ROLLBACK WORK
(PERFORM ON COMMIT/ROLLBACK)

• Object-oriented handling of classical dynpros, including selection screens as a replacement for


dialog transactions, CALL SCREEN and CALL SELECTION-SCREEN

• Dynamic generation of classes as a replacement for the classical dynamic program generation
(GENERATE SUBROUTINE POOL)

• Direct support of background processing as a replacement for the call of

• executable programs (SUBMIT VIA JOB)

In these cases, the following classical processing blocks can still be created in new programs:

• Function modules are still required for RFC and the update and are recommended for the call of
classical dynpros and selection screens.

• Subroutines are still required for PERFORM ON COMMIT/ROLLBACK and in dynamically


generated subroutine pools (GENERATE SUBROUTINE POOL).

• Dialog modules and event blocks for selection screen events are still required in function groups
that wrap the classical dynpros and selection screens.

• The START-OF-SELECTION event block is still required in executable programs that are intended
for background processing.

Within this type of processing block, however, the execution should be delegated immediately to a suitable
method This does not have to be a method of a global class, but it can be located in the associated main
program within the scope of a local class. To ensure that the system implements the same stricter check
in these processing blocks as in the methods, the obsolete statements check (OO context) can be
activated in the extended program check.

2.1.3.2 Bad example

The following source code contains a rudimentary implementation for handling different types of bank
accounts in a function group and their use in a program. Only the “withdrawal of an amount” function is
shown. The function modules of the function group work on external data that is loaded into a global
internal table in the LOAD-OF-PROGRAM event. An input parameter checks whether money is being
withdrawn from a checking account or a savings account. Next, the handling is delegated to various
subroutines using a CASE-WHEN control structure. No reuse takes place. The subroutines access the
global internal table. The function module for withdrawing money is called for different accounts in an
application program. Classic exception handling is performed using further CASE-WHEN control
structures for querying sy-subrc.

Page: 23 of 227
FUNCTION-POOL account.
DATA account_tab TYPE SORTED TABLE OF accounts
WITH UNIQUE KEY id.
LOAD-OF-PROGRAM.
"fetch amount for all accounts into account_tab
... ..
.

FUNCTION withdraw.
*"-----------------------------------------------------
*" IMPORTING
*" REFERENCE(id) TYPE accounts-id
*" REFERENCE(kind) TYPE c DEFAULT 'C'
*" REFERENCE(amount) TYPE accounts-amount
*" EXCEPTIONS
*" negative_amount
*" unknown_account_type
*"------------------------------------------------------
CASE kind.
WHEN 'C'.
PERFORM withdraw_from_checking_account
USING id amount.
WHEN 'S'.
PERFORM withdraw_from_savings_account
USING id amount.
WHEN OTHERS.
RAISE unknown_account_type.
ENDCASE.
ENDFUNCTION.
FORM
withdraw_from_checking_account
USING l_id TYPE accounts-id
l_amount TYPE accounts-amount.
FIELD-SYMBOLS <account> TYPE accounts.
ASSIGN account_tab[ KEY primary_key id = l_id ] TO <account>.
<account> = <account> - l_amount.
IF <account> < 0.
"Handle debit balance
...
ENDIF.
ENDFORM.
FORM
withdraw_from_savings_account
USING l_id TYPE accounts-id
l_amount TYPE accounts-amount.
FIELD-SYMBOLS <account> TYPE accounts.
ASSIGN account_tab[ KEY primary_key id = l_id ] TO <account>.
IF <account>-amount > l_amount.
<account>-amount = <account>-amount - l_amount.
ELSE.
RAISE negative_amount.
ENDIF.
ENDFORM.
*********************************************************

Page: 24 of 227
PROGRAM bank_application.
...
CALL FUNCTION 'WITHDRAW'
EXPORTING
id = ...
kind = 'C'
amount = ...
EXCEPTIONS
unknown_account_type = 2
negative_amount = 4.
CASE sy-subrc.
WHEN 2.
...
WHEN 4.
...
ENDCASE.
...
CALL FUNCTION 'WITHDRAW'
EXPORTING
id = ...
kind = 'S'
amount = ...
EXCEPTIONS
unknown_account_type = 2
negative_amount = 4.
CASE sy-subrc.
WHEN 2.
...
WHEN 4.
...
ENDCASE.

2.1.3.3 Good example

The following source code contains a rudimentary implementation for handling different types of bank
accounts in classes and their use in a class. Only the “withdrawal of an amount” function is shown.

The different types of accounts are implemented in subclasses of an abstract class for accounts. Each
instance of an account is provided with the required data in its constructor. If required, the application
class generates instances of accounts of the required type and uses their methods polymorphically by
means of a superclass reference variable. Exception handling is carried out using class-based exceptions.
CASEWHEN control structures are not required. As already explained in separation of concerns, no
overhead code is generated here when using classes, compared to procedural programming.

CLASS cx_negative_amount DEFINITION PUBLIC


INHERITING FROM cx_static_check.
ENDCLASS.
CLASS cl_account DEFINITION ABSTRACT PUBLIC.
PUBLIC SECTION.
METHODS: constructor IMPORTING id TYPE string,
withdraw IMPORTING amount TYPE i
RAISING cx_negative_amount.
PROTECTED SECTION.
DATA amount TYPE accounts-amount.
ENDCLASS.

Page: 25 of 227
CLASS cl_account IMPLEMENTATION.
METHOD constructor.
"fetch amount for one account into attribute amount
...
ENDMETHOD.
METHOD withdraw.
me->amount = me->amount - amount.
ENDMETHOD.
ENDCLASS.
CLASS cl_checking_account DEFINITION PUBLIC
INHERITING FROM cl_account.
PUBLIC SECTION.
METHODS withdraw REDEFINITION.
ENDCLASS.

CLASS cl_checking_account IMPLEMENTATION.


METHOD withdraw. super-
>withdraw( amount ).
IF me->amount < 0.
"Handle debit balance
...
ENDIF.
ENDMETHOD.
ENDCLASS.
CLASS cl_savings_account DEFINITION PUBLIC
INHERITING FROM cl_account.
PUBLIC SECTION.
METHODS withdraw REDEFINITION.
ENDCLASS.
CLASS cl_savings_account IMPLEMENTATION.
METHOD withdraw. IF me-
>amount > amount.
super->withdraw( amount ).
ELSE.
RAISE EXCEPTION TYPE cx_negative_amount.
ENDIF.
ENDMETHOD.
ENDCLASS.
********************************************************
CLASS bank_application DEFINITION PUBLIC.
PUBLIC SECTION.
CLASS-METHODS main.
ENDCLASS.
CLASS bank_application IMPLEMENTATION.
METHOD main.
DATA: account1 TYPE REF TO cl_account,
account2 TYPE REF TO cl_account.
...
CREATE OBJECT account1 TYPE
cl_checking_account EXPORTING id = ...
CREATE OBJECT account2 TYPE cl_savings_account
EXPORTING
id
= ... ...

Page: 26 of 227
TRY.
account1->withdraw( ... ). account2-
>withdraw( ... ).
CATCH cx_negative_amount.
...
ENDTRY.
ENDMETHOD.
ENDCLASS.

2.2 Programm Type and Program Properties


As soon as you create an ABAP program you make an important decision about its robustness and
maintainability by selecting its program type and attributes. Among other things, the program type and
program attributes determine how strict the syntax check is. Another important property of a program (as
well as all other development objects) is its original language.

Program Type

2.2.1.1 Background

Every ABAP program has a program type that specifies which declarations and processing blocks a
program can contain, and how it can be executed using the ABAP runtime environment. These are the
possible program types in ABAP:

• Executable program
An executable program can contain all possible declarative statements. All processing blocks are
possible except for function modules. The program supports classic dynpros and selection
screens. It can be executed using the statement SUBMIT or using transaction codes. Executable
programs are created in ABAP Editor.

• Class pool
A class pool always contains declarative statements for a global class. It can also include
declarative statements for local types, interfaces, and classes. Only methods can be used as
processing blocks. The pool does not support classic dynpros or selection screens. Global class
methods can be called externally (depending on visibility) and public methods of the global class
can be executed using transaction codes. Class pools are created using Class Builder.

• Interface pool
An interface pool can only contain the declarative statements for a global interface. Processing
blocks, classic dynpros, and selection screens are not possible. Interface pools cannot be called
or executed and are created using Class Builder.

• Function group (function pool)


A function group can contain all types of declarative statements. All processing blocks are
supported except for the reporting event blocks. Classic dynpros and selection screens are
supported. The associated function modules can be called, but it is also possible to access
dynpro processing of the function group by using transaction codes. Function groups using
Function Builder.

• Module pool
A module pool can contain all possible declarative statements. All processing blocks are
supported except for reporting event blocks and function modules. The module pool supports

Page: 27 of 227
classic dynpros and selection screens. It can be executed using transaction codes. Module pools
are created using ABAP Editor.

• Subroutine pool
A subroutine pool can contain all possible declarative statements. The LOAD-
OFPROGRAM event block, subroutines and methods can be used as processing blocks. The
pool does not support classic dynpros or selection screens. The subroutines can be called, but it
is also possible to execute methods using transaction codes. Subroutine pools are created using
ABAP Editor.

• Type group (type pool)


A type group can contain the declarative statements, TYPES and CONSTANTS.
Processing blocks, classic dynpros, and selection screens are not possible. Type groups cannot
be called or executed. Type groups are created using ABAP Dictionary.

In addition to these compilation units (programs that can be compiled independently), include programs
can also be used for source code organization.

In ABAP, a program execution means that the system loads a program into the memory and executes one
or more of its processing blocks. A distinction is made between standalone and called program execution:

• Standalone program execution


When programs are executed as standalone programs, the program is started using a
transaction code (statements CALL TRANSACTION and LEAVE TO TRANSACTION) or using
the statement SUBMIT for an executable program. The statement SUBMIT also allows
execution in a background process.

• Called program execution


In called program executions, a running program calls a procedure (method, function module, or
subroutine) of another program. If necessary, this other program is loaded into the internal
session of the calling program.

• The program flow for standalone program execution depends on the selected program type and
the type of program call:

• If the program is called using a transaction, a distinction is made between object-oriented (OO)
transactions and dialog transactions. For object-oriented transactions, the transaction code is
linked to a method of a local or global class. This method defines the program flow. Dialog
transactions, however, are associated with a classic dynpro of the program. In this case, the
program flow is defined by the associated dynpro flow logic.

• The program flow of an executable program that was started using SUBMIT is defined by the
reporting process of the ABAP runtime environment. The runtime environment calls the different
reporting event blocks (START-OFSELECTION, GET and END-OF-SELECTION) of the program.

• The program type must be selected based on the technical program attributes described here and
the requirements for program execution. Not all the program types mention here are appropriate
for new developments.

2.2.1.2 Rule

Select the appropriate program type

Page: 28 of 227
To select the program type, proceed as follows:

• The program type "class pool" or "interface pool" is automatically set for global classes and
interfaces.

• To implement completed functions that are to be displayed in the class library, use the program
type "subroutine pool" can be used for local classes.

2.2.1.3 Details

The above hierarchy for selecting the program type is derived from the basic rule described, which defines
the use of ABAP Objects. The following list describes specific aspects in detail:

• If ABAP Objects functionality needs to be provided across the whole package or system, this is
achieved using global classes or interfaces that implicitly have the program type "class pool" or
"interface pool". The call is performed using a method call or an OO transaction (if a standalone
program execution is required).

• The "subroutine pool" program type can be used to implement completed functions called using a
transaction code (not using a method call), and which do not require passed parameters and do
not have a user interface. Only local classes are used for implementation. The program is called
using an OO transaction. Subroutine pools - as the name suggests - were originally intended for
subroutines that were called from other programs. Subroutines (and calling subroutines externally
in particular) are declared as obsolete, according to the existing programming guidelines.
Subroutine pools no longer have this purpose. Instead, subroutine pools are suggested as
independent containers for local classes. This is because they are otherwise barely affected by
implicit processes of the ABAP runtime environment.

• Remote-enabled function modules (RFM) - which provide functionality using the RFC interface
across servers or across systems, or are used for parallelization - can only be created in a
function group. The implementation of the actual functionality, however, is carried out in a class,
for example, in a local class within the function group.

• The same applies to update function modules (which are called for the update using CALL
FUNCTION IN UPDATE TASK) as to RFMs.

• Programs with a classic dynpro interface or selection screens (if still required) should also be
created as a function group. The function group only implements the UI but does not contain its
own application logic (based on the SoC principle). This program type is suitable because it can
contain both classic dynpros and an external functional interface in the form of function modules.
The dialog modules of the function group called by the dynpro flow logic should only contain
method calls, for instance, for methods of local classes.

• An executable program includes several event blocks that are executed when the various
reporting events occur. This form of event control is largely obsolete and should no longer be
used. Executable programs should only be used where they are technically required, thus mainly
for background processing. In this case, the actual implementation should also be carried out in
methods, for example, methods of a local class within the executable program. The event block of
the initial event, START-OF-SELECTION, should only contain a method call. No other event
blocks should be included anymore.

• The module pool used to be the program type traditionally used for classic dialog programming
with dynpros. The Separation of Concerns concept is not sufficiently supported by module pools.

Page: 29 of 227
This is why no more new module pools should be created. Instead, any classic dynpros that are
still required should be wrapped in function groups.

• The type group program type was initially implemented as a temporary solution. This was
because it was not always possible to define types for internal tables in ABAP Dictionary. The
same applied to the global storage of constants. Both gaps have now been closed. In ABAP
Dictionary, any types can be defined. In global classes and interfaces, types and constants can be
created for package-wide or system-wide use. Therefore, the "type group" program type is
obsolete, and no new type groups should be created.

• If required, the program type "function group" is set automatically for function modules. In
addition, function groups must be used to wrap classic dynpros or selection screens.

• If the programs needs to be executed within the scope of background processing, the executable
program type is automatically set.

• New module pools or type groups should no longer be created.

2.2.1.3.1 Note

In cases where program types other than class and interface pools are still used, the check Obsolete
Statements (OO Context) should be activated in the extended program check. This enables same
stringent syntax check to be implemented for program components not implemented in local classes as
for within classes.

Program Attributes

2.2.2.1 Background

Alongside various, less important properties, each ABAP program has a set of program attributes that
control specific aspects of the program behavior and syntax check severity:

• Unicode checks active For creating a Unicode program

• Fixed point arithmetic


For respecting the decimal separator for operations with packed numbers.

• Logical database
For connecting an executable program with a logical database.

The program attributes are defined when a program is created the relevant tool (Class Builder, Function
Builder, ABAP Editor). It is possible to change them later.

2.2.2.2 Rule

Use the default settings for program attributes

Set the program attributes for new programs as follows:

• Unicode Checks Active activated

• Fixed Point Arithmetic activated

Page: 30 of 227
• No assignment to a logical database

When a new program is created, these settings are the same as the default values. This means that they
can be applied without making any changes. Once the program attributes are set they should no longer
be modified.

2.2.2.3 Details

Different behaviors or check severities are only provided for compatibility reasons, to ensure that existing
programs can still be compiled and executed. New programs should definitely not use obsolete settings.

• When a new program is created, the Unicode Checks Active attribute is already set by default.
This attribute must never be reset. Activating the Unicode checks is the only way to ensure that
the program can be executed in Unicode systems and in non-Unicode systems, and that the
same results are returned in both cases. A program with activated Unicode checks is referred to
as a Unicode program. A Unicode system represents an SAP system, where characters are
displayed in Unicode format (ISO/IEC 10646). (Currently UTF-16 with platform-dependent byte
order. Here, the ABAP programming language supports the subset covered by UCS-2.) In a
Unicode system, only execute Unicode programs can be executed. However, Unicode programs
can also be executed in non-Unicode systems. The programs provided by SAP are usually
Unicode programs. When a non-Unicode system is prepared for the switch to Unicode, all existing
non-Unicode programs must be implemented as Unicode programs. Activating the Unicode
checks is only beneficial for the developer (for example, a more stringent static type check and a
stricter separation of byte and character string processing).

• When a new program is created, the Fixed Point Arithmetic attribute is already set by default.
This attribute must never be reset. If fixed point arithmetic is disabled, the position of the decimal
separator of packed numbers (type p) is only respected for output in a classic dynpro, in
assignments to fields of the types c and string, or for formatting using WRITE TO. The position is
not respected for calculations. Today, this behavior only rarely meets the developer’s
expectations. If the calculation is to be carried out with packed numbers without any decimal
places, this must be specified using the DECIMALS 0 addition for the declaration.

• When a new executable program is created, the Logical Database attribute is empty. This
attribute assigns executable programs to a logical database. This enables the selection screen
and flow of the program to be combined with the selection screen and flow of the logical
database. A logical database is a special development object that is edited in Logical Database
Builder and which provides other ABAP programs with data from the nodes of a hierarchical tree
structure. A logical database has a hierarchical structure, an ABAP database program and a
separate standard selection screen. Logical databases should no longer be used. This is because
they are based on cross-program usage of global data, implicit subroutine calls and reporting
event control, and therefore do not comply with modern concepts. The function module
LDB_PROCESS can be used to access existing logical databases. This function module can be
called from a method. No new logical databases should be created. Instead a relevant service
should be made available using a global class.

Because any later changes to the program attributes potentially involve extra work, the correct attributes
should be configured right from the start and not changed later. It is particularly important for attributes
that influence the syntax check (currently the Unicode check) that the highest possible check severity is
chosen. This ensures the best preparation for any subsequent switches.

The following sections assume that only the Unicode check is used and fixed point arithmetic is activated
and that logical databases are not used. These guidelines no longer contain a special rule for obsolete or
problematic language constructs, which are only available if the Unicode checks are switched off. These
constructs are only mentioned briefly in regard to the list of obsolete language elements.

Page: 31 of 227
2.2.2.3.1 Note

From Release 740, SP05, the strict modes in the Open SQL syntax check demand Unicode programs in
which the program attribute fixed point arithmetic is switched on.

2.2.2.3.2 Example

In the following source code performs a substring write across two numeric components of a structure.

METHOD ...
DATA:
BEGIN OF struct,
comp1 TYPE i,
comp2 TYPE i, END
OF struct.
struct+2(4) = 'XXXX'.
ENDMETHOD.

This is only possible in non-Unicode programs. Here an implicit casting of the subarea is performed for
type c. The result in the components depends on the alignment gaps, the internal presentation of numeric
values (byte order), and the code page used. Therefore, the result is extremely platform-dependent. A live
program must never contain this type of code. This type of code often results in incorrect data or runtime
errors that are difficult to trace.

The above code results in a syntax error, when used in an ABAP program where the Unicode Checks
Active attribute is selected in the program properties (in accordance with the above rule). Unwanted
substring accesses are prohibited, just like any other unwanted accesses to structures or other parts of
the working memory. If these accesses cannot be identified by the syntax check, a runtime error occurs
with a descriptive short dump while the program is running.

Original Language

2.2.3.1 Background

When a new repository object, such as a program, class, or database table in ABAP Dictionary, is created,
its original language must be specified. This is specified implicitly as part of the current logon language. All
translatable texts created as part of a development object in a development project (including descriptive
short texts and long texts, the text elements of a program, and the documentation of data types or
interfaces) are assigned the specified original language. The texts are created in other languages in a
translation process (triggered by development) from the original language into the target languages.

Once specified, there is currently no technical support for the replacement of an original language by
another language across an entire project.

2.2.3.2 Rule

Defining the Original Language at Project Level

Before implementation, consider carefully which original language you want to use for for your repository
objects at project level. Developers may only create their development objects in the original language
defined for this project (or occasionally subproject).

2.2.3.3 Details

Page: 32 of 227
Proceed as follows when defining the original language:

• If all development groups involved in a project share a native language, then define this language
as the original language of all development objects (this is known as monolingual development).

• If the development groups are multilingual,

o then the original language of all development objects is either a language understood by all
developers involved (usually English, also called monolingual development)

o or the original language of development objects in those parts of the project where the main
developers share a native language is used (multilingual development).

Monolingual development groups are a best-case scenario, but are not always possible nowadays. The
two possible scenarios for multilingual development groups, either monolingual or multilingual
development, meet two different and contradictory requirements:

• When you log on to a system in a language other than the original language, there is no effective
way of working with development objects (either new or being developed) until a translation of the
relevant texts has been created in the appropriate target language. Translation usually takes
place in a follow-on translation system and has to be transported back to the development
system. This means that an efficient development process is only possible if a single original
language is defined at the beginning for the entire project, particularly in international
development groups (often

working in more than one location). All people involved in the development and validation process
can then use the product, even if only for test purposes. If monolingual development is
implemented in multilingual development groups, therefore, some (if not all) developers in a
project need to create texts in a language other than their native language.

• There are usually no tools or processes available for linguistic and stylistic checks on UI texts and
documentation written by developers in a language other than their native language. Ideally,
developers working on user dialogs and documentation should create texts in their native
language and these texts should then be translated by trained translators into their own native
language, using predefined terminology.

This second point is the reason why English is not required to be the one and only original language for all
development projects, and why monolingual development groups should be free to work in their native
language, with follow-on translation if required.

If a development group is multilingual, the original language of each development object must be decided
case by case. Generally, the first point wins, since international development teams require monolingual
development to be able to use their development resources most effectively for a particular project. In
some cases, for example where subprojects require large volumes of text to be created, it could be best to
define the native language of the developers as the original language. This is particularly relevant in
SAP's in-house development teams, where many German-speaking developers continue to work.

In multilingual projects, it is best develop associated business functions in a single language (at least at
package level). Table contents should also be created in a single language.

2.2.3.3.1 Note

The original language is defined as the logon language when a repository object is created, which is why
the logon language is used intentionally for creating and editing repository objects.

Page: 33 of 227
2.2.3.3.2 Note

Regardless of whether a development project is monolingual or multilingual, consistent terminology must


be defined for all texts created in the project and used across the board. In multilingual development
projects, the translation of the terminology into the relevant languages should be completed before
development start if possible, so that the terms can be used by the developers. The existing standards for
UI texts and documents must also be followed.

2.3 Modern ABAP


Background
ABAP is a living programming language that is continually being developed. Since its introduction some
30 years ago, new ABAP programs have been developed continually, with work to advance the ABAP
language ongoing at the same time. Developments to the ABAP language are either extensions of the
existing language attributes to implement new functionality, or the replacement of existing functionality
with more advanced concepts. The replacement of existing language elements with new ones usually
makes the existing language elements superfluous or obsolete. The most prominent example of a
development of the ABAP language is still the implementation of ABAP Objects.

With regard to the ABAP language, SAP has committed itself to a policy of strict downward compatibility.
This means that an ABAP program written for release 3.0, for example, can be executed on an AS ABAP
in release 7.0 or higher - provided that you are using a non-Unicode system. On the other hand, this also
means:

• An experienced developer will have had little impetus to break with old habits and engage in new
concepts. The only exception is the changeover to Unicode systems, where ABAP programs have
to be converted into Unicode programs with slightly changed syntax rules.

• ABAP beginners get confused by the multitude of options available for the same task. Where
there is doubt, older programs are used as templates, and the obsolete concepts are frequently
still used instead of the new ones.

To remedy these problems, you can use the following simple rule.

Rule
Do Not Use Obsolete Language Elements

Do not use obsolete language elements for new developments. We also recommend an incremental
changeover to new concepts as they become available.

Details
Newer language elements are always the better language elements. Obsolete language elements are
only provided for downward compatibility reasons. A statement or statement addition is declared as
obsolete only when a more powerful alternative exists or when the language element is identified as being
prone to errors (in the sense that it invites insecure and non-robust programming). For this reason, secure
and robust programming is not possible if obsolete language elements are used, which makes the use of
such obsolete language elements out of the question for new developments.

If ABAP Objects is used, the majority of the obsolete statements and additions are already prohibited
syntactically. For this reason among others, we strongly recommend using ABAP Objects. Outside of

Page: 34 of 227
ABAP Objects, that is, in cases that are still allowed, you must make sure that no obsolete language
elements are used. Obsolete Language Elements provides an overview of the obsolete statements and
statement additions.

2.3.3.1 Bad Example

The following source code shows the solution of a task using obsolete language elements. A procedure is
supposed to replace all occurrences of substring in a text with a new character string new if the substring
is not at the end of a word.

FORM bad_example USING substring TYPE csequence


new TYPE csequence
CHANGING text TYPE
csequence. DATA: pattern TYPE string,
subrc TYPE sy-subrc.
CONCATENATE '*' substring INTO pattern.
SEARCH text FOR pattern.
IF sy-subrc <> 0.
CLEAR subrc.
WHILE subrc = 0.
REPLACE substring WITH new INTO text.
subrc = sy-subrc.
ENDWHILE.
ENDIF.
ENDFORM.

In the above source code, aside from the modularization with FORM - ENDFORM, the statement
SEARCH and the used variant of REPLACE are obsolete. Furthermore, a character string operator
&& is available as a replacement for CONCATENATE.

2.3.3.2 Good Example

The following source code executes the same task as above; however, it uses the latest available
language elements.

METHOD good_example.
FIND REGEX substring && `\b` IN text.
IF sy-subrc <> 0.
REPLACE ALL OCCURRENCES OF substring IN text WITH new.
ENDIF.
ENDMETHOD.

The subroutine is replaced with a method. By using FIND in connection with a regular expression, which is
composed using the character string operator &&, you no longer require any help variables.
The WHILE loop is replaced with REPLACE ALL OCCURRENCES, which means it is unnecessary to use
another help variable, and the control flow is moved to the ABAP runtime environment. The latter
increases the execution speed and helps to limit the maximum nesting depth.

2.3.3.3 Note

In connection with the above rule, the question on the coexistence of old and new concepts within a
program unit arises. There is only one area in which this is clearly syntactically defined, that is, the use of
the classical and the class-based exception concept in processing blocks. Otherwise, obsolete language

Page: 35 of 227
elements can be directly next to new language elements in a program part. In this context, we recommend
keeping the use within a context as consistent as possible, that is, do not use different statements, such
as FIND and SEARCH, in parallel for the same purpose.

However, this does not mean that in enhancements to existing procedures you should continue to use
obsolete language elements to keep consistency, just because they already exist. Rather, you should
seize the opportunity to switch the entire procedure to the corresponding new language elements. By
using module tests to cover the procedures to be changed, you can ensure that there will be no
unpleasant surprises during the changeover.

2.4 Checks for Correctness


This section enhances the section Correctness and Quality by providing more information about static
checks on ABAP programs.

Syntax Check

2.4.1.1 Background

The syntax check provides syntax errors and syntax warnings:

• As soon as a syntax error occurs, the system stops the check and displays the relevant error
message. In many cases, the system suggests a correction that can be applied. Programs with
syntax errors can be activated, but they cannot be generated and executed. In the extended
program check, the syntax errors are reported as fatal errors. Syntax errors must be corrected at
all costs.

• If a syntax warning occurs, the syntax check is not terminated. The program can still be executed.
The syntax warnings are displayed in ABAP Editor after the syntax check and the extended
program check. Of course, testing tools that include the checks of the extended program check
(such as Code Inspector and ABAP Test Cockpit) also display syntax warnings. When a program
is activated, the system only displays syntax warnings if syntax errors have occurred at the same
time. The warnings reported by the syntax check are subdivided into three priorities that are only
displayed by the extended program check:

o Priority 1
Errors that could cause program termination if the ABAP program is executed. This priority
also includes all constructs that should not be used at all, because they indicate program
errors and are very likely to make the program behave incorrectly.

o Priority 2
This priority refers to all constructs that do not necessarily cause incorrect behavior, but
are obsolete, for example, and should be replaced by current constructs. Priority 2 errors
can become priority 1 errors or syntax errors in future releases.

o Priority 3
Includes all errors where correction would be beneficial, but not necessarily essential, for the
current release. However, the possibility of raising the priority in future releases is not ruled
out.

The severity of the ABAP syntax check is determined by the decisions that were made when the
program was created. In this way, program constructs that produce only syntax warnings outside of
classes or in obsolete non-Unicode programs can represent real syntax errors in classes or in Unicode

Page: 36 of 227
programs. Selected syntax warnings can be suppressed by using pragmas. A pragma is a program
directive that affects specific checks but does not influence the program flow.

2.4.1.2 Rule

Take notice of syntax warnings

Take all warnings of the ABAP syntax check seriously. Syntax warnings are not permitted in completed
programs.

2.4.1.3 Details

The causes of syntax warnings must always be corrected because they generally produce unpredictable
errors. These warnings are often reclassified as errors by SAP in subsequent AS ABAP releases. In this
case, a program that initially only included syntax warnings is syntactically incorrect and can no longer be
used after an upgrade. Exactly the same behavior is displayed when switching from non-Unicode
programs to Unicode programs or when migrating older program parts to ABAP Objects.

Selected syntax check warnings can be hidden using pragmas. With respect to the package check,
selecting Package Check as Server in Package Builder is the first step to achieving real encapsulation.. It
enables users of development objects to modify their where-used positions before hard syntax errors
occur. For this reason, all package check warnings must be corrected to ensure that the program's syntax
remains correct, even after increased encapsulation of the packages used.

2.4.1.3.1 Bad example

The following source code causes a syntax warning. An internal table is accessed using a freely specified
key, even though a secondary key with the same components exists. This access performs a linear
search.

FIELD-SYMBOLS <fs> TYPE spfli.

DATA itab TYPE HASHED TABLE OF spfli


WITH UNIQUE KEY carrid connid
WITH NON-UNIQUE SORTED KEY cities COMPONENTS cityto cityfrom.
..
.

READ TABLE itab WITH KEY cityfrom = '...' cityto = '...'


ASSIGNING <fs>.

2.4.1.3.2 Good example

The following source code corrects the above example. Here, the secondary key is used to access
the table. The access performs a binary search. Hiding the syntax warning using the associated
program primkey is not recommended here.

FIELD-SYMBOLS <fs> TYPE spfli.

DATA itab TYPE HASHED TABLE OF spfli


WITH UNIQUE KEY carrid connid
WITH NON-UNIQUE SORTED KEY cities COMPONENTS cityto cityfrom.
..
.

Page: 37 of 227
ASSIGN itab[ KEY cities
COMPONENTS cityfrom = '...' cityto = '...' ] TO <fs>.

Extended Program Check

2.4.2.1 Background

The extended program check for activated programs can be called either from ABAP Workbench or by
using transaction SLIN. It performs static checks that are too complex for the normal syntax check. Both
individual and multiple subtests can be performed, or an ATC check that includes important subtests.

The extended program check outputs errors, warnings and messages. The ATC-relevant check reports
errors and warnings that are particularly critical. These checks are also performed in program checks in
ABAP Test Cockpit (ATC). The classification of individual results (error, warning or message) depends
on whether an ATC-relevant check is performed or explicitly selected individual checks. The extended
program check also displays the errors and warnings of the syntax check.

In the initial screen of the extended program check, a programming guidelines check can also be
selected. This checks whether certain rules presented in this book (that can be verified statically) have
been adhered to.

The messages from the extended program check, which are inapplicable in some special cases, can be
hidden using pragmas. Before the introduction of pragmas, it was not possible to hide messages raised by
a normal syntax check.

2.4.2.1.1 Note

The extended program check also covers security checks used to test ABAP programs for all potential
security risks. In customer systems, these checks are subject to a special licensing procedure.

2.4.2.2 Rule

Use the extended program check

Use the extended program check and take the results seriously. Message are not allowed to appear when
the ATC checks are performed for a completed program.

2.4.2.3 Details

The errors, warnings and messages output by the extended program check are just as important as the
syntax errors and syntax warnings from the syntax check. For example, an error reported by the extended
program check can indicate that a program will definitely lead to a runtime error when it is executed.
Warnings and messages usually indicate a questionable use of language elements, which is likely to
cause unexpected program behavior.

In rare cases, when a result reported by the extended program check is not justified, this must be
documented using an appropriate pragma (the relevant pragma is indicated in the message). This means
that the system suppresses the message of the extended program check. Ideally, in less obvious
situations, an additional comment should be used to describe why the message is not applicable.

2.4.2.3.1 Note

Page: 38 of 227
The extended program check provides useful help for writing ABAP programs in the correct way. Using
unspecific pseudo comments or pragmas can undo the positive effect of the extended program check. In
particular, the following statement should never be used:

SET EXTENDED CHECK OFF.

This statement suppresses all messages of the extended program check for an entire source code
section.

If the ABAP program is submitted to a code review, the results of the extended program check should be
used to evaluate the quality.

2.4.2.3.2 Bad example

If the following source code is checked using the extended program check, a warning appears. It indicates
a particularly questionable query of the content of the return value sy-subrc.

ASSIGN field TO <fs>.

IF sy-subrc <> 0.
...
ENDIF.

The program section shows a typical error in a syntactically correct program. The developer wrongly
assumes that the static form of the ASSIGN statement sets the sy-subrc system field, which is not the
case. The developer wrongly believes that he has secured his program. An incorrect program behavior
occurs if sy-subrc has a value that is not zero, due to previous statements. Therefore, the main advantage
of the extended program check is that the system does not just examine individual statements for
syntactic correctness, but it also examines entire program sections for semantic errors.

2.4.2.3.3 Good example

The following source code shows the corrected version of the above example. The predicate expression
IS ASSIGNED is used (as recommended in the documentation) instead of sy-subrc. The message from
the extended program check could also be hidden using a pragma (##subrc_read), but this is not
recommended in this case because the extended program check indicates a real problem.

ASSIGN field TO <fs>.

IF <fs> IS ASSIGNED.
...
ENDIF.

Code Inspector

2.4.3.1 Background

The Code Inspector tool performs a static check of repository objects regarding performance, security,
syntax, and adherence to naming conventions. Transaction SCI can be called to use the full range of
functions of Code Inspector to perform complex static checks and regular mass tests for large numbers of
development objects.

Code Inspector can also be called from ABAP Workbench to perform a standard set of checks for the
current object, for example by choosing Program → Check → Code Inspector in ABAP Editor. The

Page: 39 of 227
standard check variant used here contains most of the checks from the extended program check, as well
as a few additional security and performance checks. Code Inspector can also be integrated into the
release of transports.

As in the extended program check, the results of Code Inspector are divided into three categories (errors,
warnings, and simple messages), which you can hide using special pseudo comments.

2.4.3.2 Rule

Use the standard Code Inspector check variant

Perform the standard check variant of Code Inspector before releasing a program, and correct all error
messages.

2.4.3.3 Details

If the extended program check is used, the standard check variant of Code Inspector only reports
messages and checks that are not covered by the extended program check. These are mainly messages
relating to potential performance or security risks in programs. Examples are messages about
unfavorable WHERE conditions in a SELECT, a pass by value instead of a pass by reference for
parameters, or non-secure program calls.

Compared with the messages of the extended program check, it is not always so easy to correct these
problems at their source, perhaps because there is no other option for a selection, or because the
transparency or robustness of a construct is seen as more important than a small potential loss of
performance.

In such cases, the messages can be suppressed using the appropriate pseudo comments. A pseudo
comment is a clear indication to the reader of a program that the program author has performed the
relevant checks and has explicitly suppressed the message for a good reason. If necessary, pseudo
comments can be substantiated by additional normal comments.

2.4.3.3.1 Bad example

A standard Code Inspector run for the example class below issues warnings because an internal table is
returned by pass by value and an inner join for database tables with activated SAP buffering is used in
the SELECT statement.

CLASS class DEFINITION FINAL.


PUBLIC SECTION.
TYPES: BEGIN OF docu_wa,
object TYPE dokil-object, dokldate
TYPE dokhl-dokldate, dokltime TYPE dokhl-
dokltime, END OF docu_wa,
docu_tab TYPE SORTED TABLE OF docu_wa
WITH NON-UNIQUE KEY object.
METHODS get_docu
IMPORTING VALUE(langu) TYPE sy-langu
EXPORTING VALUE(documents) TYPE docu_tab.
ENDCLASS.

CLASS class IMPLEMENTATION.


METHOD get_docu.
SELECT d~object, h~dokldate, h~dokltime

Page: 40 of 227
FROM dokil AS d
INNER JOIN dokhl AS h
ON h~id = d~id AND
h~object = d~object AND
h~typ = d~typ AND
h~langu = d~langu AND
h~dokversion = d~version
WHERE d~id = 'SD' AND
d~object LIKE 'AB%' AND
d~typ = 'E' AND
d~langu = @langu
INTO CORRESPONDING FIELDS OF TABLE @documents.
ENDMETHOD.
ENDCLASS.

2.4.3.3.2 Good example

The source code below shows the corrected version of the above class, for which Code Inspector no
longer issues any messages.

The pass by value of the internal table is replaced by a pass by reference. For the transfer of the
elementary parameter langu, the pass by value is left unchanged to ensure robustness. In the standard
check used, it would not have triggered a warning in any case. If Code Inspector displays a warning in a
case such as this, it can be hidden by using the pseudo comment "#EC CI_VALPAR.

The inner join of the SELECT statement bypasses the SAP buffering; this would lead to performance
problems if the method was called frequently. However let us assume (for purpose of this example) that
the method is part of a larger application, where shared objects ensure that the selected data is buffered.
In this case, the inner join should be used instead of other constructs with poor performance, such as a
nested SELECT loop. As a result, the warning from Code Inspector is hidden using the pseudo comment
#EC CI_BUFFJOIN. The reasons for this are described in a regular comment.

CLASS class DEFINITION FINAL.


PUBLIC SECTION.

TYPES: BEGIN OF docu_wa,


object TYPE dokil-object, dokldate
TYPE dokhl-dokldate, dokltime TYPE dokhl-
dokltime, END OF docu_wa,
docu_tab TYPE SORTED TABLE OF docu_wa
WITH NON-UNIQUE KEY object.
METHODS get_docu
IMPORTING VALUE(langu) TYPE sy-langu "#EC CI_VALPAR
EXPORTING REFERENCE(documents) TYPE docu_tab.
ENDCLASS.

CLASS class IMPLEMENTATION.


METHOD get_docu.
SELECT d~object, h~dokldate, h~dokltime "#EC CI_BUFFJOIN
FROM dokil AS d
INNER JOIN dokhl AS h "Buffering is done
ON h~id = d~id AND "by application
h~object = d~object AND "with Shared Objects
h~typ = d~typ AND
h~langu = d~langu AND
h~dokversion = d~version

Page: 41 of 227
WHERE d~id = 'SD' AND
d~object LIKE 'AB%' AND
d~typ = 'E' AND
d~langu = @langu
INTO CORRESPONDING FIELDS OF TABLE @documents.
ENDMETHOD.
ENDCLASS.

ABAP Test Cockpit

2.4.4.1 Background

ABAP Test Cockpit (ATC) is a framework that is integrated into ABAP Workbench; it simplifies
considerably the handling of the tests required during development. ATC makes it possible to execute and
display results for various tests on development objects, for example:

• Extended program checks

• Static performance tests

• Module tests with ABAP Unit

• Static usability tests

• Package checks

• Security Checks

Whereas Code Inspector is only integrated into the development environment by way of the standard
check and can otherwise only be used by calling a separate transaction, ATC is completely integrated into
Object Navigator and Transport Organizer, and is available there for tests during development. ATC allows
quality managers to perform mass tests. In the ABAP Development Tools (ADT), some tests are provided
only from ATC.

2.4.4.2 Rule

Configuring and Using ABAP Test Cockpit Correctly

If ABAP Test Cockpit is available in your system, make sure that an ATC run is performed on all involved
development objects and that no messages are displayed before you release the objects for transport.
The ATC check should be integrated directly into the transport release.

2.4.4.3 Details

ATC is a tool that can be used both by SAP developers and as part of central quality assurance
management. For example, if a developer checks all development objects of a package in the
development system using the same ATC configuration used by a quality manager as part of a mass run
in a consolidation system, he can go ahead and correct all messages without having to wait for feedback
from the quality manager.

If ATC is configured correctly, the above rule includes the previous rules for syntax warnings, extended
program checks, and Code Inspector.

Page: 42 of 227
2.4.4.3.1 Notes

• More specifically, the security checks in the extended program check can be
executed and managed from ATC, which makes their integration into the
transport release possible.

• Outside of SAP, ATC is available from the following releases: o SAP

NetWeaver AS ABAP 7.0, EhP2, Support Package 12 o SAP NetWeaver AS

ABAP 7.0, EhP3, Support Package 05 o SAP NetWeaver AS ABAP 7.3,

EhP1, Support Package 05 o SAP NetWeaver AS ABAP 7.4, Support

Package 02

3 STRUCTURE AND STYLE


This section covers all aspects of a program that have no direct influence on its functionality. These
aspects remain hidden to users when they use the program. However, structure and style are very
significant for the traceability of the program flow by a human viewer. The source code must be designed
in such a way that a person other than the program developer can work with it properly. There are many
situations in which this is necessary, for example:

• A review or code inspection is taking place.

• Another developer needs to examine the program in order to process an error message (hotline,
development support).

• The program has been completely transferred from the development department to the
maintenance department, where it is maintained and possibly developed further.

• A program that was delivered by an organization (for example, SAP) is to be modified or


developed further in other organizations (for example, at SAP partners or customers).

A sound program structure and programming style is very important beyond these situations as well,
because developers need to be able to quickly orient themselves in their code even if they have not
worked on the program for a while.

Source code needs to be read and understood time and time again during the software lifecycle. In
practice, it is not realistic for any program that contains more than a few lines that source code can be
delivered just once and will require no further maintenance. As well as complying with general standards
such as functional correctness and performance, a program must be developed in such a way that its
source code meets the requirements of the human reader.

The following guidelines help produce comprehensible and traceable ABAP source codes. Of course,
since #beauty is in the eye of the beholder#, opinions on style vary from individual to individual and are
the topic of much discussion. For this reason, the following recommendations are limited to those issues
for which there is general consensus. These are mostly generally accepted guidelines that often apply to
any programming language. The aim here is not to dictate a specific programming style, but rather to
ensure an appropriate programming style. A developer must feel at home with his own sources so that he
can work efficiently. Stringent style specifications can sometimes do more harm than good.

Page: 43 of 227
3.1 Source Code Formatting
The readability of source code is dependent to a great extent on formatting that highlights its logical
structure. The following methods help to format source code in a clear way.

Uppercase/Lowercase

3.1.1.1 Background
In contrast to many other modern programming languages, ABAP is not case-sensitive for ABAP words
(tokens of an ABAP statement that express its semantics; either ABAP keywords or additions) nor for
operators and names of operands. The only exception is dynamic programming, where the names of
operands usually have to be specified in uppercase.

3.1.1.2 Rule
No Mixed Uppercase and Lowercase in Names
Use only lowercase or uppercase in an individual token. Use uppercase for keywords and lowercase for
operands.

3.1.1.3 Details
The usage of upper or lower case for tokens, that is ABAP words and names, used to be a very important
aspect for the formatting of the source code. A uniform adherence to upper or lower case made it easier
for the reader to differentiate keywords and names. Due to the syntactic source code coloring in the ABAP
Editor, this aspect has become less important; however, the above rule is still valid because of the
following reasons:
Syntactic source code coloring is generally not visible when source code is printed. Therefore, a uniform
rule for using upper and lower case is useful for emphasizing the difference between keywords and
names.
Because the usage of upper and lower case in ABAP source code has no syntactic significance outside of
character literals (that is, text field literals in inverted commas (#), string literals in back quotes (`), and
character string templates in vertical lines (|)), the ABAP development environment is not designed to
maintain it permanently outside the mentioned constructs. The Pretty Printer only offers the alternatives to
use only lowercase or only uppercase, or to use either uppercase or lowercase for keywords and
lowercase or uppercase respectively for names in operand positions.
Because of the second point, it does not make sense in ABAP to use upper and lower case as a
selfdefined means of style. In other words, the names should not be written in mixed case style (also
referred to as camel case style; see the following example), as is very popular in languages in which case
sensitivity is taken into account. A consistent notation cannot be ensured due to the missing syntactic
relevance. A mixed notation will be lost sooner or later when the Pretty Printer is used, even if this is
unintentional. Moreover, it possibly prevents other developers from using the Pretty Printer after changes
have been made to the source code. Use of the Pretty Printer is explicitly recommended.

3.1.1.3.1 Example
When the program PGL_UPPER_LOWER_CASE is executed, source code is displayed in the ABAP Editor;
the upper part shows the declaration of a class with names in mixed case style or camel case style. Here,
uppercase marks the beginnings of words within a combined name.
The code provided here as a bad example approximately follows the Java convention, and in the eyes of
many beholders it might look better than the following good example. However, its appearance is less
important than the mentioned technical restrictions, which do not currently allow such a naming. Executing
the Pretty Printer would irreversibly spoil the code's appearance because the names would then be
illegible.
The lower part of the source code shows the declaration of a class in ABAP style, where which words
within combined names are separated by underscores (_). These separations cannot get lost when you
use the Pretty Printer.

Page: 44 of 227
Once the program has been called, the example is formatted according to the proposed Pretty
Printer setting, with ABAP words in uppercase and operands in lowercase. Irrespective of its configuration,
the separation of the words in the names would remain after each execution of the Pretty Printer.

3.1.1.3.2 Note
The built-in character string functions, to_mixed and from_mixed allow conversions between names in
ABAP style with underscores and names in mixed case style or camel case style, which can be helpful for
data exchange with external systems.

Statements per Program Line

3.1.2.1 Background
An ABAP statement (declaration or executable statement) is closed with a period. This statement can be
followed by further statements in the same line. Statements can also be split over several lines.

3.1.2.2 Rule
Maximum of one statement per program line
Write a maximum of one statement in every source code line. Long statements can and should be split at
suitable places. This means the statements can be divided up across consecutive lines.

3.1.2.3 Details
Using several statements in one line makes the source code harder to read. If a line contains an entire
control structure, the lack of indentations makes it especially difficult to identify the logical structure.
Therefore you should try to avoid using more than one statement in a program line.
Besides reduced readability, using several statements in a line can also make the code more difficult to
debug. Even in single steps, ABAP Debugger stops a maximum of once per executable program line. This
makes it impractical for the debugging process if there is more than one statement in a line.
If a statement is split over several lines (which occurs frequently due to the potential length of complex
ABAP statements), there should be no spaces between the parts of the statement. The breaks in the
statement should occur at semantically suitable places so that groups with a similar semantic meaning are
next to each other, if possible. Indentations should be used to ensure that the statement is as well
structured and readable as possible.

3.1.2.3.1 Bad example


The following source code shows a syntactically correct program section which is poorly laid out and
difficult to understand. Even the Pretty Printer can barely improve the layout of the template displayed
here.
CLASS class DEFINITION.
PUBLIC SECTION. METHODS meth. ENDCLASS.
CLASS class IMPLEMENTATION. METHOD meth.
DATA: itab TYPE TABLE OF dbtab, wa TYPE dbtab.
SELECT * FROM dbtab WHERE column = ' ' INTO TABLE @itab.
IF sy-subrc <> 0. RETURN. ENDIF.
LOOP AT itab INTO wa. ... ENDLOOP.
ENDMETHOD. ENDCLASS.

3.1.2.3.2 Good example


The following source code shows the same code as above but with the recommended limit of one
statement per line. The complex SELECT statement contains numerous clauses and is spilt accordingly
over several consecutive lines.
CLASS class DEFINITION.

Page: 45 of 227
PUBLIC SECTION.
METHODS meth.
ENDCLASS.
CLASS class IMPLEMENTATION.
METHOD meth.
DATA: itab TYPE TABLE OF dbtab,
wa TYPE dbtab. SELECT *
FROM dbtab
WHERE column = ' '
INTO TABLE @itab.
IF sy-subrc <> 0.
RETURN.
ENDIF.
LOOP AT itab INTO wa.
...
ENDLOOP.
ENDMETHOD.
ENDCLASS.

Using Pretty Printer

3.1.3.1 Background

The alignment of ABAP statements in the source code is not specified syntactically. There should be a
maximum of one statement per line, which can be technically indented and wrapped as required. This makes
control structures visible. By inserting blank lines, related source code sections can be grouped, which makes
the code easier to read. Note that in ABAP statements, blank characters cannot be added or left out at random.
For example, tokens must be separated by at least one blank character (especially with operands and
operators). In a method call, no blank characters are permitted between the name of the method and the left
bracket.

Languages with a C-like syntax (where statement blocks within control structures are delimited by curly
brackets) provide an inexhaustible source for discussions on how to best make indentations. However, for
ABAP the solution is obvious: Every introductory statement (such as IF) has an associated concluding
statement (in this case, ENDIF). Event blocks for ABAP runtime environment events are the only exception
here. They are introduced by a statement (such as START-OF-SELECTION) but are not concluded with the
associated concluding statement. Instead, they are concluded with the next event block. However, event blocks
should only be used in exceptional cases. Introductory and concluding statements are aligned at the same
level; the block content is indented.

Pretty Printer can modify the indentation of control structures and the capitalization of keywords and names in
the source code at any time (even in display mode).

3.1.3.2 Rule

Use Pretty Printer consistently and universally

Use Pretty Printer to format source code consistently. If Pretty Printer cannot format the code as required,
manual changes are necessary.

3.1.3.3 Details

We recommend that the use of Pretty Printer to make indentations required to make the source code easy to
read. This guarantees that the indentations are consistently based on the logical control structure and that the

Page: 46 of 227
indentation depth is identical for each program. Implementing this type of formatting by hand is prone to errors
and not recommended.

Even though Pretty Printer can be used to adapt the source code to any other style (using the available
settings), a consistent and universal style should be selected. The reason for this is that version management
and the correction workbench are not designed to ignore purely stylistic differences between source code
versions. Therefore, the following Pretty Printer settings are recommended for consistent source code
formatting. These settings cover the expectations and working habits of most ABAP developers:

• Indent statements
Absolutely essential for a logical program structure that is clearly visible. A maximum of one statement
per program line is allowed.

• Do not insert standard comments


The standard comment only contains redundant information and it is not adapted, if the source code is
changed.

• Keyword Uppercase
Makes it easier to understand the source code in printed form. In this case, syntax color-coding is
usually not visible.
The code needs to be edited manually, to ensure the correct use of blank lines between related source code
blocks. Syntactic units, such as classes, methods, control blocks, or semantic units of a program, should be
separated from one another with one or two blank lines (depending on their size and meaning). However, there
should not be more than two blank lines in succession.

3.1.3.3.1 Note

We recommend that the use of the Keyword Lowercase setting in Pretty Printer, for reasons of visual clarity.
This is because repository object names and data objects names in the ABAP Debugger are displayed in
uppercase, in all tools required for ABAP development. With the Keyword Lowercase setting, the source code
format matches this display format. For example, reading COLUMN columns form a DBTAB database table:

select COLUMN1 COLUMN2 ...


from DBTAB into corresponding
fields of ITAB where COLUMN
= FIELD.

Names in uppercase are also more suitable because many dynamic operand positions in ABAP still require
uppercase. A good example is an almost static call of function modules. With the Keyword Lowercase setting,
the call of a function module FUNCTION_MODULE would be as follows:

call function 'FUNCTION_MODULE' exporting PARAMETER = FIELD.

However, the Keyword Lowercase setting was added to Pretty Printer relatively late and could not compete
against the more common setting Keyword Uppercase. In addition, the ABAP syntax diagrams and sample
programs in ABAP documentation, as well as all relevant publications, are formatted with the Keyword
Uppercase setting. If we recommended the use of the Keyword Lowercase setting, this would lead to confusion
and would not help the programming guidelines to be universally accepted.

3.1.3.3.2 Bad example

The following source code shows the above example, but without indentations and only with lowercase. The
highlighted ABAP words (shown in bold here and in color in the ABAP Editor) might not appear in a program
printout. This would make the program even less legible.

class class definition.

Page: 47 of 227
public section. methods
meth.
endclass. class class
implementation. method
meth. data: itab type table
of dbtab, wa type dbtab.
select * from
dbtab into table
itab where
column = ' '. if sy-
subrc <> 0.
return. endif. loop
at itab into wa.
... endloop.
endmethod
. endclass.

Line Width

3.1.4.1 Background
The alignment of ABAP statements in the source code is not specified syntactically. There should be a
maximum of one statement per line, which can be technically indented and wrapped as required. This
makes control structures visible. By inserting blank lines, related source code sections can be grouped,
which makes the code easier to read. Note that in ABAP statements, blank characters cannot be added
or left out at random. For example, tokens must be separated by at least one blank character (especially
with operands and operators). In a method call, no blank characters are permitted between the name of
the method and the left bracket.
Languages with a C-like syntax (where statement blocks within control structures are delimited by curly
brackets) provide an inexhaustible source for discussions on how to best make indentations. However, for
ABAP the solution is obvious: Every introductory statement (such as IF) has an associated concluding
statement (in this case, ENDIF). Event blocks for ABAP runtime environment events are the only
exception here. They are introduced by a statement (such as START-OF-SELECTION) but are not
concluded with the associated concluding statement. Instead, they are concluded with the next event
block.
However, event blocks should only be used in exceptional cases. Introductory and concluding statements
are aligned at the same level; the block content is indented.
Pretty Printer can modify the indentation of control structures and the capitalization of keywords and
names in the source code at any time (even in display mode).

3.1.4.2 Rule
Use Pretty Printer consistently and universally
Use Pretty Printer to format source code consistently. If Pretty Printer cannot format the code as required,
manual changes are necessary.

3.1.4.3 Details
We recommend that the use of Pretty Printer to make indentations required to make the source code easy
to read. This guarantees that the indentations are consistently based on the logical control structure and
that the indentation depth is identical for each program. Implementing this type of formatting by hand is
prone to errors and not recommended.
Even though Pretty Printer can be used to adapt the source code to any other style (using the available
settings), a consistent and universal style should be selected. The reason for this is that version
management and the correction workbench are not designed to ignore purely stylistic differences between
source code versions. Therefore, the following Pretty Printer settings are recommended for consistent

Page: 48 of 227
source code formatting. These settings cover the expectations and working habits of most ABAP
developers:
Indent statements
Absolutely essential for a logical program structure that is clearly visible. A maximum of one statement per
program line is allowed.
Do not insert standard comments
The standard comment only contains redundant information and it is not adapted, if the source code is
changed.
Keyword Uppercase
Makes it easier to understand the source code in printed form. In this case, syntax color-coding is usually
not visible.
The code needs to be edited manually, to ensure the correct use of blank lines between related source
code blocks. Syntactic units, such as classes, methods, control blocks, or semantic units of a program,
should be separated from one another with one or two blank lines (depending on their size and meaning).
However, there should not be more than two blank lines in succession.

3.1.4.4 Note
We recommend that the use of the Keyword Lowercase setting in Pretty Printer, for reasons of visual
clarity. This is because repository object names and data objects names in the ABAP Debugger are
displayed in uppercase, in all tools required for ABAP development. With the Keyword Lowercase setting,
the source code format matches this display format. For example, reading COLUMN columns form a
DBTAB database table:
select COLUMN1 COLUMN2 ...
from DBTAB into
corresponding fields of ITAB
where COLUMN = FIELD.
Names in uppercase are also more suitable because many dynamic operand positions in ABAP still
require
uppercase. A good example is an almost static call of function modules. With the Keyword
Lowercase setting, the call of a function module FUNCTION_MODULE would be as follows:
call function 'FUNCTION_MODULE' exporting PARAMETER = FIELD.
However, the Keyword Lowercase setting was added to Pretty Printer relatively late and could not
compete against the more common setting Keyword Uppercase. In addition, the ABAP syntax diagrams
and sample programs in ABAP documentation, as well as all relevant publications, are formatted with the
Keyword Uppercase setting. If we recommended the use of the Keyword Lowercase setting, this would
lead to confusion and would not help the programming guidelines to be universally accepted.

3.1.4.4.1 Bad example


The following source code shows the above example, but without indentations and only with lowercase.
The highlighted ABAP words (shown in bold here and in color in the ABAP Editor) might not appear in a
program printout. This would make the program even less legible.
class class definition.
public section.
methods meth.
endclass. class class
implementation. method
meth. data: itab type table
of dbtab, wa type dbtab.
select * from
dbtab into table
itab where column
= ' '. if sy-subrc <>
0. return. endif.

Page: 49 of 227
loop at itab into
wa.
... endloop.
endmethod
. endclass.

3.2 Naming
The naming of the repository objects defined outside of a program and of the entities declared within the
program (such as data types, data objects, and procedures) is of vital importance for understanding and
editing the program. All names used must be readable, easy to learn, and appropriate. You can meet
these requirements by using meaningful names. It is also important to avoid naming conflicts.

Choosing the Language

3.2.1.1 Background
The natural language that has established itself worldwide for computer programming is English. This is
because the language elements in all significant programming languages have been taken from English
and their syntax based on English grammar. ABAP is no exception. In fact, efforts have been made to
guarantee correct English by giving additions of related statements different names, even if they have the
same meaning. Well-known examples include the (now obsolete) additions VARYING and VARY of the
statements DO and WHILE. Here, ABAP can even be viewed as a subset of the English language.

3.2.1.2 Rule
Using names in English
Give your repository objects and your local program objects names that use English words only

3.2.1.3 Details
Using names in a language other than English looks unnatural (and inelegant) in programming languages
whose own language elements are all in English. As well as this, English names make the source code
accessible to as wide an audience as possible. Finally, using a different language throughout your code
would be difficult due to the large number of English technical terms used in today's IT environment.
In instances where British and American spelling differ, use the American spelling. This is often shorter
and more commonly used in IT.

3.2.1.3.1 Note
This rule applies regardless of the original language chosen.

3.2.1.3.2 Bad example


One of the most notorious examples of non-English names in ABAP is the component UZEIT of the
structure SYST, plus its data element SYUZEIT. All other components (with the exception of the equally
notorious DATUM (for date) and MANDT (for client)) are English terms or abbreviations.

Descriptive Names

3.2.2.1 Background
A name can include technical and semantic information:

• Technical information can be very versatile. Examples of options in a data object: data type,
declaration context, whether a procedure parameter is passed by value or by reference.

Page: 50 of 227
• The semantic information indicates the purpose of classes or data types, the content of data objects,
how methods work, and so on.

The technical information about a repository object or internal program entity can be viewed directly in ABAP
Workbench. This information is also displayed in tooltips or can be displayed with a simple double-click.
However, in contrast to purely technical type information, the semantics of a variable are more difficult to
identify without the relevant information in the name.

3.2.2.2 Rule

Use descriptive names


Always choose names that include the semantic information required for your context and that also easy to
understand.

3.2.2.3 Details

The aim is to assign descriptive and self-documenting names. You should always follow a problem-oriented
approach instead of an implementation-oriented approach. For example, a truth value should not be named
flag. Instead it should have a name that indicates its meaning, such as is_checked.

When you select a descriptive, problem-oriented name, you should consider the following aspects in particular:

• Appropriate use of nouns, verbs, and adjectives

• Meaningful use of abbreviations

• Appropriate separation of name components

These points are discussed in detail in the following sections. The purely technical information for a named
object can be displayed quickly and easily, using double-click navigation in ABAP Workbench. Therefore, this
information can be omitted from names and semantic information can be used in names instead.

Any organizations (within SAP or external) that want to specify technical information in addition to semantic
information in names, can define their own naming conventions that are based on our semantic rules. However,
we believe that encoding technical attributes in names is not suitable for making ABAP programs (developed
according to the present guidelines) easier to understand and maintain. This may be different in the context of
other programming languages with fewer types and less powerful development environments.

The use of nouns, verbs, and adjectives for naming depends on the entity that you want to name:

• Packages and package interfaces


A package comprises a collection of repository objects for a specific subject area. The package name
can either consist of one or more singular nouns that describe the subject area (such as
sabp_compiler), or one or more plural nouns that indicate the contained objects (such as
sabp_analyze_tools). Subpackages start with the name of the super package and contain suffixes that
indicate the specialization. The name of a package interface starts with the name of the package.
Information about visibility or restrictions for certain users are attached as an optional suffix. For
example, _public, stands for public interface and _verification stands for interface to verification tools.

• Data types, classes, and interfaces


They denote categories of things and are therefore named using nouns, for example,
cl_abap_codepage. The greater the degree of specialization, the greater the number of nouns required
for description. This can result in longer, combined names, for instance, if_abap_string_writer or
cl_abap_xml_name_converter. If necessary, the name can be further specified with an additional
adjective, as in if_serializable_object and cl_abap_weak_reference. The name of a category is usually

Page: 51 of 227
written in the singular form. Therefore, a class name should generally consist of singular nouns.
However, there are many examples of deviations from this rule, such as cl_abap_ memory_utilities.
These classes often do not model a category but instead provide a hodgepodge of loosely related
functions, usually in the form of exclusively static methods.

• Associations
An association refers to a semantic relationship between a start object and a target object. To make
sure this relationship is unambiguous when an association is used in a path, you should prefix the
association with TO_. This should be followed by a name that contains the name of the target object (in
the case of non-reflexive associations).
• Variable data objects and procedure parameters
These describe properties and are therefore named with a noun, for instance, cl_abap_regex->pattern.
Truth values are labeled using the is_ prefix, which is consistent with natural language usage. If the
property you want to describe is a quantity (usually an internal table in ABAP), this should be expressed
using the plural. For example, the matches parameter of the cl_abap_matcher->find_all method.

• Constants
From a technical point of view, these are data objects with unchangeable values at program runtime.
They describe special, unchangeable properties. Values of constants are described with nouns. They
are distinguished by a specific property (such as minimum size, start value) expressed by one or more
additional adjectives. Examples: cl_abap_exceptional_values=>decfloat34_max and
cl_abap_format=>o_extended_monetary.

• Events
They are named using an expression in present perfect that describes their occurrence, for example,
cl_dd_form_element->button_clicked and cl_gui_alv_ tree->selection_changed. In this example, the
noun is abbreviated significantly (o for output format). More information about useful abbreviations can
be found below.

• Procedures
New procedures are methods according to the use ABAP objects rule. Here, we distinguish between
different cases:

o Event handlers are named after the corresponding event. They are assigned a prefix that identifies
them as handler methods. In ABAP, the on_ prefix has established itself. This is consistent with
natural language use and clearly labels a method as an event handler. For the two event examples
above, the names of the corresponding handler methods would be on_ button_clicked and
on_selection_changed.

o The name of methods with a return value (functional methods) describes the returned result. The
get_ prefix is added to describe the task of the method. An example of this is the
cl_abap_exceptional_values=>get_max_value method. If the method returns a truth value, is_ is
used as a prefix instead of get_. In ABAP, these get_ methods are intended to identify the return
value (by using a calculation, for example). Unlike in Java, for example, no own methods should be
used to simply return attribute values. Instead you should use the write-protected (READ-ONLY)
attributes provided in ABAP.

o In all other cases, the name of a method describes an activity to be performed. Therefore, the
method name is a verb, generally expressed in the imperative. Examples: cl_abap_regex->create_
matcher and cl_abap_memory_utilities=>do_garbage_collection. Methods used to set attributes
are described using the relevant attribute, which is prefixed with set_. Other procedures (function
modules and subroutines) required to wrap method calls are named accordingly.

• Exception
Exceptions describe unexpected states. Technically they are classes. Classic exceptions should no
longer be used. Except for the prefix, the same considerations apply here. To distinguish exceptions

Page: 52 of 227
from normal classes, they are assigned their own prefix cx_, provided that they are global exception
classes. The name of an exception reflects the rejected state as clearly as possible, for instance,
cx_sy_offset_not_allowed. If an entire hierarchy of exception classes exists, the names of the
superclasses do not describe special exception situations. Instead they describe error categories (such
as cx_ sy_data_access_error in this example).

You should avoid using abbreviations as name components wherever possible. Exceptions to this rule are
abbreviations that are usually used instead of the complete term, such as GUI or XML. However, if the use of
certain abbreviations cannot be avoided due to restricted space, you should initially use common abbreviations.

If no common abbreviation exists, you should proceed as follows: Vowels are omitted, unless they are the first
letter of the word. They are of minor significance for the recognition value. If a word starts with a double vowel,
both letters are kept for ease of recognition (for example, outbnd as the abbreviation for outbound instead of
otbnd). If further abbreviations are required, you can replace double consonants with single consonants. Even
after this step, the word is generally still recognizable.

An example of a poorly chosen abbreviation would be tstmp for timestamp. This abbreviation does not follow
the above rules and is not intuitive. Readers would probably initially think of the possible components tst or tmp,
which would remind them of test or temporary. However, an association to timestamp is in initially very difficult
to identify. Therefore, if you create abbreviations, you must ensure that the result is not similar to another,
possibly more common abbreviation for a completely different term.

When you create abbreviations in a foreign language, you run the risk that the result represents a word or
abbreviation with a completely different meaning. If in doubt, you should enter the abbreviation in a search
engine to check it. For example, you only have four characters available and you want to use the word button.
In this case, you should select the abbreviation bttn (following the abbreviation rules above), instead of the first
four characters.

As a rule, name components should be visually separated using underscores in ABAP. This makes the names
easier to read. Separating name components with uppercase and lowercase (common in languages with C-like
syntax) is not useful in ABAP. Underscores normally identify a name, because ABAP words are usually not
formed this way. The only exceptions here are certain format options for character string templates (such as
SCIENTIFIC_ WITH_LEADING_ZERO), which can only occur within character string expressions, and certain
additions of SELECTION-SCREEN and WRITE.

You should not use digits as name components. They are often a sign of poorly selected names (because they
are not very descriptive) or indicate the use of several individual variables, where the use of an internal table
would make more sense. Exceptions include the interface parameters of procedures. Numbering similar
parameters definitely makes sense here.

The use of digits to form phonetic names is also problematic because they require a degree of familiarization,
and their meaning is not always obvious to everyone. A particularly bad use of digits is the abbreviation trmn8r
for terminator. The commonly used 2 for to is the only justifiable exception here. This is often found as a name
component in conversion procedures and can be interpreted easily (convert_itf_2_html, for example).

3.2.2.3.1 Note

You must always keep in mind that the information included in a name must remain valid. This applies to
semantic information, but especially to technical information. If, for example, technical information included in a
name changes due to a refactoring measure, all relevant names and their users must be modified. However,
this is not an easy task in released interfaces. If in doubt, remember that names containing incorrect information
are worse than names that do not provide any information at all. This is why programming guidelines exist that
suggest only using nondescript names. Since semantic properties are less likely to change in the course of
(further) development than technical properties, our predominantly semantic specifications for naming are
relatively well safeguarded from program changes.

3.2.2.3.2 Note

Page: 53 of 227
Less is often more. Our suggestions indicate how to compose names to include the information that is
necessary in a context. They should only be used when the meaning of the name is not completely obvious
from the context. For example:

METHOD do_something.
CONSTANTS lcv_maximum_do_loop_count TYPE i VALUE 100.
DO lcv_maximum_do_loop_count TIMES.
...
ENDDO.
ENDMETHOD.
The long name lcv_maximum_do_loop_count is quite difficult to read. A method can only include a manageable
number of statements. Therefore, you can select a very simple name in simple cases:

METHOD do_something.
CONSTANTS nmax TYPE i VALUE 100.
DO nmax TIMES.
...
ENDDO.
ENDMETHOD.

A further example of where short names are useful is help fields declared in LET expressions.

3.2.2.3.3 Bad example

The following source code shows the declaration of a class that executes arithmetic calculations. This should be
understood as a synthetic naming example. Of course, in ABAP, it makes absolutely no sense to wrap the
arithmetic operations on elementary numeric data types using a class. The names of the class and its methods
are unnecessarily short, and the names of the method parameters have no semantic meaning at all.

CLASS calcltr DEFINITION.


PUBLIC SECTION.
METHODS: add IMPORTING a TYPE i
b TYPE i
RETURNING VALUE(c) TYPE i,
sub IMPORTING a TYPE i
b TYPE i
RETURNING VALUE(c) TYPE i,
mul IMPORTING a TYPE i
b TYPE i
RETURNING VALUE(c) TYPE i,
div IMPORTING a TYPE i
b TYPE i
RETURNING VALUE(c) TYPE f.
ENDCLASS.

3.2.2.3.4 Good example

The following source code shows the same class as in the code above, but the names of the class and its
methods are now spelled in full, and the names of the method parameters indicate their semantic meaning.

CLASS calculator DEFINITION.


PUBLIC SECTION.
METHODS: add IMPORTING addend1 TYPE i
addend2 TYPE i
RETURNING VALUE(sum) TYPE i,
subtract IMPORTING minuend TYPE i
subtrahend TYPE i

Page: 54 of 227
RETURNING VALUE(difference) TYPE i,
multiply IMPORTING factor1 TYPE i
factor2 TYPE i
RETURNING VALUE(product) TYPE i,
divide IMPORTING dividend TYPE i
divisor TYPE i
RETURNING VALUE(quotient) TYPE f.
ENDCLASS.

Because the addition and multiplication operands are commutative, you can use digits here to distinguish them.

Names of Repository Objects

3.2.3.1 Background

Repository objects are development objects edited using the tools in ABAP Workbench. Each repository object
is assigned to a package. Packages encapsulate the repository objects contained and use package interfaces
to make objects available that should be usable outside the package. This complies with the SoC principle.

From a semantic point of view, packages represent a context for declarations, which is one level above the
contexts of an ABAP program. Unlike the contexts of an ABAP program (programs, classes, procedures), a
package does not generate a separate namespace.

The namespace for repository objects is defined as follows:

• Prefix namespace
Development organizations (SAP departments, SAP partners, and SAP customers) can request a prefix
namespace for their own development systems. A prefix namespace has a name with at least 5 and a
maximum of 10 digits, and the first digit and last digit must be slashes (/.../). After the namespace has
been assigned, repository objects only can be created in systems, where the namespace is enabled by
prefixing the namespace name /.../. If a package is created in this type of prefix namespace, it can only
contain repository objects belonging to the same namespace. However, multiple packages can be
created within a single prefix namespace. The available length for the actual name is reduced by the
length of the namespace prefix, including the slashes.

• Customer namespace
If no prefix namespace is available, the names of repository objects created in customer systems or
non-SAP development systems must have Y or Z as the first character. This means they are located in
the customer namespace. Repository objects whose names start with Z can also be located within
packages whose names start with Y and the other way round.

• SAP namespace
If no prefix namespace is available, there are no real restrictions for the names of repository objects
that are created in SAP’s own development systems. The SAP namespace comprises the entire AS
ABAP. Regardless of the namespace where a repository object resides, the name of the repository
object is unique in the current AS ABAP. Therefore, when the object is addressed, nothing else needs
to be specified. The namespaces (particularly the prefix namespace) were implemented to avoid
namespace conflicts during transports between systems and upgrades. For SAP’s own development
systems, there is a cross-system table that ensures the uniqueness of names within the SAP
namespace.

3.2.3.2 Rule

Linc has a registered Customer Namespace Z/Y which must be the prefix for all new objects.

Page: 55 of 227
In addition new objects should follow a certain pattern, which makes them on the one hand easier to recognize
and on the other hand easier find by other developers:

z[Module][Object-Type][Localization]_[Descriptive_Name]

• [Module] has to follow the official SAP module abbreviation (FI / CO / SD / …)


• [Object-Type] should be the 1-2 character abbreviation for DDIC objects
• [Localization] should either be “WW” for “WorldWide” or the 2 character iso code of the region
• [Descriptive_Name] should be a meaningful name of the development object
Use common naming conventions for repository objects. The predefined name prefixes, CL_, IF_, and CX_,
apply to objects of the class library. If possible, create all repository objects in the prefix namespaces only. In
addition, use a naming convention to clearly indicate which package or component the objects belong to.

3.2.3.3 Details

Classes and interfaces are the most important entities for programming with ABAP Objects. Either a class type
or an interface type can be used to type a object reference. It is useful to uniquely flag these two types in the
class library by means of a prefix. Global exception classes should also be uniquely identified by a prefix. The
following naming conventions apply. These conventions are sometimes enforced by Class Builder but are
sometimes only evaluated:

• CL_ for global classes

• IF_ for global interfaces

• CX_ for global exception classes

• CL_BADI_, IF_BADI_, CX_BADI_ for classes, interfaces, and exception classes of Business Add-Ins
(BAdI)

In addition, the names of all repository objects should clearly identify the package or component they belong to.
Technically speaking, a package does not generate its own namespace and therefore naming requires strict
discipline. Using prefix namespaces is very helpful in itself. However, they are not intended for the package
level but for bigger development projects, which usually comprise numerous packages.

Therefore, the names of the repository objects contained in a package should be labeled with a shared name
component, which indicates the affiliation to a package or at least to an application component. The length of
names is restricted to 30 characters or less, and the namespace prefix is included. Therefore, an abbreviation
should be used for this name component and not the complete package name.

A global name should never be given for a package-specific or component-specific repository object. This would
render the name useless for further general use. For example, general names of the SAP namespace (such as
CHAR60 for a data element or CL_ABAP_MATH for a class) should only be declared in absolutely fundamental
basis packages delivered by SAP and exposed by these packages in a generally available interface.

If developers find a repository object with a global name, they naturally assume that they can freely use the
object in the way indicated by the name. Since the application of package boundaries is not checked
thoroughly, repository objects with overly global names (particularly in the SAP namespace and also in the
customer namespace) are now used throughout all AS ABAP packages. This can cause considerable difficulties
when implementing real package encapsulation.

3.2.3.3.1 Note

Page: 56 of 227
The above rule supplements the global rule regarding descriptive names. With regard to technical information in
repository object names, the same information stated in section on descriptive names also applies here (also
refer to the discussion on prefixes and suffixes in program-internal names).

All development organizations are free to create own naming conventions on the basis of the above rule
regarding descriptive names. However, note that the use of a namespace prefix only leaves limited space for
the remaining name components. For example, the names of database tables are restricted to 16 characters.
Therefore, the namespace prefix should not be too long. It should simply describe a product line using an
abbreviation

3.2.3.3.2 Exception

Not all repository objects can be created in prefix namespaces. Some examples are authorization objects and
type groups. In these cases, an additional package should be created that includes all of these objects. The
object names and package names should, if possible, contain a relevant, normal prefix instead of the real
namespace prefix /.../.

A similar guideline applies if further development is performed in areas that are traditionally located in the SAP
namespace or the customer namespace. Instead of using a real namespace prefix, this can be simulated by
using uniform prefixes when new packages and development objects are created.

If ABAP Workbench itself allocates names, for instance, for Include programs, which are assigned to specific
master programs (such as function groups or class pools), this name allocation always has priority over all other
rules. This ensures that the workbench and the compiler run correctly.

3.2.3.3.3 Example

Refer to the repository objects of the sample application in the package SABAP_DEMOS_CAR_RENTAL.

The subpackages of the SABAP_DEMOS_CAR_RENTAL package start with the same name as the
superpackage (as recommended in these guidelines). A suffix indicates their specialization. The same applies
to the package interfaces. Instead of a real namespace prefix, the repository objects of the packages have the
DEMO_ prefix. This indicates that the objects are part of a demo package. The affiliation to the car rental
application is indicated by the abbreviation CR (car rental).

Program-Internal Names

3.2.4.1 Background

Program-internal names describe entities that are declared in the program and are called within the program or
called by other programs. Typical examples include identifiers for data types and data objects as well as
methods and method interface parameters.

Program-internal declarations can be configured in different contexts that all span a separate namespace.
These contexts are arranged in the order from local to global:

1. Local declarations in a procedure (Method)


2. Declarations of instance components and static components in a class
3. Global declarations in the declaration part of a program

Here local declarations always hide the more global declarations of higher contexts. Different types of
declarations each span a separate namespace in their context, except the class components, which are all
located in one single namespace, regardless of their type.

Page: 57 of 227
The identifiers used in ABAP programs must comply with the syntactic requirements for classes in Unicode
programs (in accordance with the rule Use ABAP Objects and the rule Applying Default Settings to Program
Attributes). In other words, the identifiers must begin with a letter, which is followed other letters and numbers
that can be separated by underscores.

3.2.4.2 Rule

Prevent program-internal names from being confused or obscured

Choose program-internal names that cannot be confused with ABAP words or other declarations. In addition, a
local name must not obscure a more global name. Global entities and interface parameters of procedures
should have a prefix for identification purposes.
3.2.4.3 Details

Besides using the general rule of assigning meaningful names, it is also important for program-internal
declarations that you stick to the above rule of eliminating human error (avoiding name confusion). Unlike a
human reader, the compiler usually knows exactly what an identifier is referring to. Use the following prefixes to
avoid the danger of unwanted obscuring and name confusion:

In general all data names should follow a certain pattern:

[VISIBILITY][TYPE]_[Descriptive_Name]

VISIBILITY might be one of following abbreviations:

• G for global data objects

• L for local data objects

• T for type definitions

• I for IMPORTING parameters

• E for EXPORTING parameters

• C for CHANGING parameters

• R for RETURNING parameters

TYPE should be the 1-character abbreviation of the elementary data type ( Structure / Table / Constant / …)

You can also use compound identifiers and component selectors.

The following sections discuss the different aspects of program-internal names in detail and with a systematic
approach.

3.2.4.3.1 Confusion with ABAP Words

A basic rule in almost all naming specifications is that language statements must not be used as names in the
source code (assuming that this is permitted by the syntax). The aim of this measure is to improve readability by
preventing confusion between statements and names. In ABAP, however, it is difficult to strictly adhere to this
rule, because the vocabulary of the programming language is very extensive and is continuously growing. In
most cases, developers will not have memorized all the ABAP words that occur in all the statements and
statement additions. Also, they cannot possibly know which words will be added in future.

Page: 58 of 227
For this reason, it is not logical or feasible to completely prohibit the use of ABAP words (ABAP keywords or
additions) as names. Thanks to the color highlighting in ABAP Editor and the different capitalization rules in
operands and ABAP words (Pretty Printer), there is no risk of confusion. If in doubt, you can always use the (!)
character directly in front of a name, to distinguish it from an ABAP word with the same name in a statement.

A single ABAP word, however, usually does not represent a descriptive name. Therefore, we recommend that
you only use ABAP words as part of combined names with underscores (_), for instance, account_class instead
of class. Because the underscore is not used in most ABAP words, it is usually a good idea to distinguish
between ABAP words and names. In some very rare cases, the compiler cannot distinguish an ABAP word from
a name that is identical to the word. In these cases, the escape character (!) must be specified.

Confusion between different declarations


In classes, all components are in the same namespace. Therefore, it is not possible to have data types and
attributes with the same name within a class to avoid confusion. In the other contexts, that is, within procedures
(Methods), or for global declarations of an ABAP program, different declarations generate different
namespaces. Here it is possible to have data objects and data types with the same name. Object types (local
classes and interfaces) are in the same namespace as data types.

To avoid confusion, we recommend that you use different names for different entities, and that you do not use
the same names for data types and data objects. Exceptions to this rule are cases where the meaning of a
name is absolutely clear, for example, the declaration of a helper variable:

DATA i TYPE i.

However, it should never be the case that a data object has the name of a data type that is not the type of the
object:

DATA i TYPE f.
DATA tadir TYPE trdir.

This is both confusing and dangerous!

3.2.4.3.2 Obscuring of More Global Declarations

The names in local contexts obscure declarations with the same name in contexts that are more global. In a
method, for example, a data type declared with TYPES obscures an identically named data type of the class.
This data type then obscures the identically named data type of the program, which in turn obscures an
identically named data type from ABAP Dictionary.

Developers must ensure that a more global object (that should be used in the current context) is not hidden.
Conversely, a global object must not be accidentally used instead of a local object. The reader of the source
code should always know what a name refers to. This means when you assign names, you should try to make
sure that the local names do not hide names that are more global.

Following the KISS principle, it is recommended that local names are different from global names, because they
do not follow their conventions. This mainly refers to the names in global declarations of the current program or
in the repository. For example, a local class should never start with the cl_ prefix, a local interface should never
start with if_ prefix, and a local data object should never start with the g_ prefix.

• Within methods
In a method (in new function modules and subroutines, there should be no local declarations), there is
the danger that local names (including method parameters) can be confused with more global names.
Declarations within the implementation can also be confused with method parameters.
To prevent local data objects in a method from being confused with components of their own class, you
can explicitly address class components using the name of the class and the class component selector
(=>), or using the object reference variable me and the instance component selector (->) .

Page: 59 of 227
If there is a danger that identically named, predefined functions can be confused, you should address
the functional methods of its own class by only using one of the selectors, if the methods are used in an
operand position. However, excessive use of selectors can make the source code difficult to read.
Therefore, you have to make individual assessments here. This danger of confusion is only relevant for
short method names, however. For methods with names consisting of multiple words or names that
start with the prefixes set_, get_, or is_, there is usually no risk of confusion. Methods should always
have a manageable size, and all declarations are therefore always visible for the reader. Therefore, this
simple rule should be sufficient to make the method easy to read.
If the declaration of the method’s parameter interface is not visible in the method implementation (as in
local classes), it is useful to make an additional distinction between local data and the method
parameters. It has become customary to use the prefixes mentioned earlier to achieve this. An
alternative prefix component l could also be considered here for local data, but it ultimately represents
redundant information.
• Within classes
If you use class components, you can always avoid confusion by addressing the class components
using the name of the class and the class component selector (=>) or an object reference variable and
the instance component selector (->). The implementation of a corresponding naming convention would
lead to redundant information, which would not improve readability and would be contradictory to the
basic KISS principle. This especially applies to functional methods. Although these methods hide
identically named, predefined functions, it would be very unusual to implement a prefix that
characterizes a functional method as a method of a class.

• In programs (general)
In the global declaration part of a program, you can create local classes and interfaces, as well as
global data types and data objects.

o The names of local classes and interfaces do not follow the naming conventions for global classes
and interfaces. In other words, they cannot start with cl_ or if_, to ensure that no global declarations
are obscured. With regards to local data, you can consider the naming convention lcl_ or lif_, but
this would be redundant and not necessarily required, because a class/interface without a prefix is
always recognizable as a local class/local interface. The use of lif_ may be useful for distinguishing
a local interface from a local class.

o Data types should no longer occur in the global declaration part of a program. Global data objects
are only required for communication between ABAP and dynpro if classic dynpros are used. Since
these objects cannot names cannot be prefixed with a program name, as with class attributes
(absolute names are only possible for data types and only in dynamic specifications), you must use
the g_ prefix for global data objects, to prevent confusion with local data objects or class attributes
in method implementations. Global data objects can only exist in executable programs, module
pools, and function groups. Global classes and interfaces cannot contain any global data objects.
Therefore, a g_ prefix for class components or interface components is definitely the wrong choice.

3.2.4.3.3 Note

Naming conventions are frequently established for names within the source code that define specifications for
naming, including potential prefixes and suffixes. These specifications often get bogged down in excessive
formal strictness. Names created this way contain redundant information, are difficult to maintain and often do
not achieve the main aim of readability and self-documenting sources. Therefore, we limited our discussion to
the naming-related aspects that we consider essential and universal. Further specifications are only useful at
the level of development groups/organizations.

If prefixes and/or suffixes are used, it is common practice to store the technical properties of the described
object in these prefixes/suffixes. Apart from the fact that we do not consider it necessary to specify technical
information in names, there are so many technical properties of an object in ABAP that they cannot be mapped
using simple rules for short prefixes/suffixes. Or combinations of different technical additions often cannot be
interpreted uniquely. Some examples:

Page: 60 of 227
• With regard to the data type of a data object, there are naming conventions where "v" and "c" as
prefixes stand for "variable" or "constant" elementary data objects. Similarly, "s" and "t" as prefixes
stand for "structures" and internal "tables". The type property "elementary" is wrongly equated with
"variable" or "constant". If the properties "static variable" and "sorted table" are also supposed to be
expressed using "s", this is very likely to cause mistakes with name assignments. This makes it much
harder to achieve the goal of readable, self-documenting source codes.

• With regard to the validity area or the context of a data object, the naming conventions often stipulate
the prefixes g_ and l_ for the names of global and local data objects. We identified g_ for global data
objects as the only convention that is actually required for program-internal names. However,
simultaneously labeling all non-global objects with the prefix l_ for the local validity area is completely
redundant and does not result in any obvious benefits. It would be actually be misleading to label static
attributes of classes as global, using the prefix g_. These attributes are only valid within the class and
have completely different semantics than global data objects. The use of these attributes does not
indicate a design weakness as it is generally the case for global data objects today.

• With regard to the method parameters, we identified the prefixes i_, e_, c_, and r_ for importing,
exporting, changing, and returning parameters as possible characteristics for distinguishing from data
objects declared in the method. Apart from this, no further technical information needs to be expressed
with additional prefixes. With method parameters in particular, technical information in prefixes tends to
cause confusion rather than improve readability. For example, a prefix is_ for "importing structure"
would
conflict with the prefix is_ for "truth values", and a prefix it_ for "importing table" could easily be
understood as a general abbreviation of "internal table". If the role the parameter plays cannot be
ascertained from the descriptive name of a parameter and the procedure name, then the names
assigned are completely wrong and/or the procedure does not fulfill any clearly defined tasks. This type
of conceptual weakness cannot be fixed (even with technical prefixes).

In summary, we recommend that you should use name additions cautiously, particularly additions with technical
information. Of course, every organization is free to use these conventions, which can supplement our basic
rules. In the ABAP environment - with its high versatility of types, many contexts, the distinction between pass
by reference and pass by value - it is probably not an easy task to create a complete, self-contained, consistent,
technically correct, and — above all — easy-to-understand set of rules for prefixes and suffixes. The known
results are just pure conventions that are usually incomplete and are not always applicable.

3.2.4.3.4 Bad example

The example shown below demonstrates how to obscure names in different contexts. The fact that no
descriptive names were used for the data objects (for the sake of simplicity) can be disregarded here.

DATA a1 TYPE string VALUE `a1 global`.


DATA a2 TYPE string VALUE `a2 global`.
DATA a3 TYPE string VALUE `a3 global`.
DATA a4 TYPE string VALUE `a4 global`.
DATA a5 TYPE string VALUE `a5 global`.
CLASS demo DEFINITION.
PUBLIC SECTION.
METHODS main
IMPORTING a1 TYPE string DEFAULT 'a1 imported'
RETURNING value(a6) TYPE string.
CLASS-DATA a1 TYPE string VALUE `a1 class`.
CLASS-DATA a2 TYPE string VALUE `a2 class`.
DATA a3 TYPE string VALUE `a3 class`.
DATA a4 TYPE string VALUE `a4 class`. ENDCLASS.
CLASS demo IMPLEMENTATION.
METHOD main.
DATA a3 TYPE string VALUE `a3 local`.

Page: 61 of 227
DATA a4 TYPE string VALUE `a4 local`.
CONCATENATE a1 demo=>a2 me->a3 a4 a5
INTO a6 SEPARATED BY `, `.
ENDMETHOD.
ENDCLASS.

If you just consider the implementation of the main method in the CONCATENATE statement, it is clearly
evident only for the demo=>a2 and me->a3 operands that they are attributes of the class and that a4 is a local
data object of the method. It is only possible in the general overview to see that a1 describes an importing
parameter, a5 describes a global data object of the program, and a6 describes a returning parameter. The
global data objects a1 to a4 cannot be addressed in the method because they are obscured by local data
objects or attributes of the class.

3.2.4.3.5 Good example

Unlike the source code above, the following source code includes the previously discussed prefixes, to prevent
obscuring and to distinguish method parameters from local data objects. Again, descriptive names were not
used here to focus on aspects that are essential for this example.

DATA g_a1 TYPE string VALUE `g_a1 global`.


DATA g_a2 TYPE string VALUE `g_a2 global`.
DATA g_a3 TYPE string VALUE `g_a3 global`.
DATA g_a4 TYPE string VALUE `g_a4 global`.
DATA g_a5 TYPE string VALUE `g_a5 global`.
CLASS demo DEFINITION.
PUBLIC SECTION.
METHODS main
IMPORTING i_a1 TYPE string DEFAULT 'i_a1 imported'
RETURNING value(r_a6) TYPE string.
CLASS-DATA a1 TYPE string VALUE `a1 class`.
CLASS-DATA a2 TYPE string VALUE `a2 class`.
DATA a3 TYPE string VALUE `a3 class`.
DATA a4 TYPE string VALUE `a4 class`. ENDCLASS.
CLASS demo IMPLEMENTATION.
METHOD main.
DATA a3 TYPE string VALUE `a3 local`.
DATA a4 TYPE string VALUE `a4 local`.
CONCATENATE i_a1 demo=>a2 me->a3 a4 g_a5
INTO r_a6 SEPARATED BY `, `.
ENDMETHOD.
ENDCLASS.

All operands are now clearly recognizable in the CONCATENATE statement. A prefix (l_) can be implemented
for the local names, but this is unnecessary for two reasons:

• The declaration is defined near the place of usage and is always visible to the reader.

• If you consistently use the selectors -> and => to address the attributes of a class, all names without a
prefix and with no specified class or a reference variable can be identified as local data objects.

By applying the minimal naming convention used here, you can address all data objects that are declared in the
displayed source code section in the method. Of course, the declaration of the global data objects is only
implemented to demonstrate obscuring and how to prevent it. Global data objects should no longer be used in
programs that do not work with classic dynpros.

Page: 62 of 227
3.2.4.3.6 Note
These guidelines deliberately use the term naming and not naming conventions. The term "programming
guidelines" is frequently equated with naming conventions. Many of the current programming guidelines
are mainly concerned with the definition of prefixes and suffixes, which are more or less meaningful.
However, we pursue a different approach here. Part of these guidelines is rightly dedicated to the
discussion of meaningful names. However, this discussion does not represent the core of these
guidelines.
A maintenance organization is responsible for maintaining monolithic ABAP applications that have evolved
over time and that may include complex procedures without a clearly defined task, large quantities of
global data objects and cryptic/misleading names. For this type of organization, the appeal for strict
naming conventions with standardized prefixes and suffixes may be understandable. However, the current
programming guidelines are designed to support the new development of robust ABAP programs, which
can be developed and maintained cost-efficiently. Consequently, it would be wrong to insist on naming
conventions (for new developments) that address problems in older code, which are excluded from the
outset anyway, if the programming meets current standards.

The rules on naming listed below meet the requirements of modern ABAP development. The only
disadvantage is that it is difficult to use automatic checks, to monitor whether these requirements are
adhered to. Our rules address human readers (and not automated test tools), who want to understand
ABAP programs and eliminate ambiguous elements as quickly as possible. With regards to older code,
we recommend refactoring based on the basic guidelines presented here. This enables you to get down
to the root of maintenance problems. If you simply try to retroactively change names in line with technical
naming conventions, you are only attempting to cure the symptoms and not the problem itself.

3.3 Comments
Comments do not influence how a program is executed and are ignored by the computer. People who work with
the source code, however, benefit greatly from comments, since they make the code easier to understand.

There are two categories of comments in ABAP:

• Comment Lines

A comment line contains a comment and nothing else. It can be defined either by the * character at the
start of the program line, or by the " character at any point of a program line blank to its left.

• End of line comments

An end of line comment is a comment added using the " character and located on the right of an ABAP
statement or part of an ABAP statement.

A comment line or end of line comment can have any content and this content is ignored when the program is
generated using ABAP Compiler.

Modification Log and Flower Box


Modification Log should also follow the same rules as above.

An example for both situations would be

* XXX_001 INS, BEGIN

Page: 63 of 227
…….
…….

* XXX_001 INS, END

In case there are single line of code insertion “ XXX_001 INS

In case there are single line of code modification “ XXX_001 MOD

Above XXX denotes the initials of the developer. If the name of the developer is Mack Johnson, the initials
would be MJO. The 3 digit number identifies the sequence of the change which is always increasing.

Flower box should be always maintained in the Top Include of the Report, main include of the Function
Group, etc. The pattern should be as follows –
************************************************************************
* MODIFICATION PROTOCOL
************************************************************************
* No. Date Author Change Transp.Requ GMP.
Tracing
* Ref. No.
*-----------------------------------------------------------------------
* MJO_001 08.02.2016 USER_ID HPSM CR TRANSPORT Y/N Process
ID
* User Name
* -> Description of the change
* In case of multiple lines should be mentioned like this
* The changes should be described well enough here
************************************************************************
The sequence of the modification logs should be in descending order, the latest on the top.

Choosing the language

3.3.2.1 Background

The natural language that has established itself worldwide for computer programming is English. This is
because the language elements in all significant programming languages have been taken from English and
their syntax based on English grammar. ABAP is no exception. In fact, efforts have been made to guarantee
correct English by giving additions of related statements different names, even if they have the same meaning.
Well-known examples include the (now obsolete) additions VARYING and VARY of the statements DO and
WHILE. Here, ABAP can even be viewed as a subset of the English language.

3.3.2.2 Rule

Write program comments in English

Write all comments in ABAP programs in English only, so that as many readers as possible can understand
them and benefit from them.

3.3.2.3 Details

English comments are a basic prerequisite for distributed development at an international level. There are other
good reasons for using English as the comment language:

Page: 64 of 227
• If names are in English, the statements of an ABAP program can be considered (with a little good will)
to be English sentences. For the reader, English comments are best suited for the source code. If
comments in another language were used, this would result in a continuous switching between the
languages, which would be exhausting even for readers who can speak the languages used.

• Frequently, the unwanted retelling comments are very similar to the described ABAP statements if they
are written in English. This way, the author quickly realizes that his comment is superfluous.

3.3.2.3.1 Exception

Technical terms that originate from country-specific legislation (such as "Abgeltungssteuer" in German) or
specific abbreviations (such as DÜVO) cannot be translated meaningfully or would no longer be recognizable
after translation. Such terms should be placed in quotation marks and not be translated into English. In this
case, it should be noted that country-specific characters can be replaced with 7-bit ASCII characters. The goal
of the above rule is to enable as many users a possible to follow the program flow. This is still possible if non-IT
terms are worded in another language.

3.3.2.3.2 Note

This rule applies regardless of the original language chosen.

3.3.2.3.3 Bad example

The following source code shows a typical example of German comments, mixed with English terms, which
usually do not even follow the required notation or terminology.

"Horizontales Splittercontrol im Hilfecontainer


CREATE OBJECT splitter_h
EXPORTING
parent = help_container
rows = 1
columns = 2.
"Vertikales Splittercontrol im linken Container
CREATE OBJECT splitter_v
EXPORTING
parent =
container_left rows =
2 columns = 1.

3.3.2.3.4 Good example

The following source code shows the above source code with English comments, as set out in the above rule.

"Horizontal splitter control in help container


CREATE OBJECT splitter_h
EXPORTING
parent = help_container
rows = 1
columns = 2.
"Vertical splitter control in left container
CREATE OBJECT splitter_v
EXPORTING
parent =
container_left rows =
2 columns = 1.

Page: 65 of 227
The goal of this example is to show the difference between German and English comments. If more meaningful
names had been chosen, that is splitter_horizontal instead of splitter_h, and so on, comments could be
dispensed with altogether, thus complying with the following rule.

Content

3.3.3.1 Background

It is usually sufficient to examine the ABAP statements to find out what happens in an implementation. However,
it much more difficult to find out why something happens. This is often only possible in a much wider context
and requires a great deal of effort.
3.3.3.2 Rule

Make meaningful comments

Write comments for your implementations that describe why something is done and not how.

3.3.3.3 Details

The best case scenario is where meaningful identifiers are used in the source code; the source code effectively
documents itself. This is the best way to document the concept of "what happens in this program section". In
this case, any additional comments that only describe obvious behavior are superfluous and do not make the
code easier to understand. There is also the risk that when changes are made to the program logic, the
associated comments are not adapted and are therefore no longer correct. In summary, these comments are
not only useless but can even be misleading and should be avoided from the start.

Conversely, developers often tend to assume that their source code is sufficiently self-documenting and leave
out descriptive comments. However, this assumption is often incorrect. This becomes apparent when a third
party tries to understand the source code (either when attempting to enhance the source code or identify a
problem). Even the authors of the code can often face this problem, if they are confronted with source code that
they wrote a long time ago and have not seen the source code since.

Even if the identifier names allow readers to easily follow what happens in the code, the question "why" often
remains unanswered. Therefore, this information must be provided as comments in the source code. This also
includes a description of the algorithms used or at least a list of their names.

3.3.3.3.1 Note

This section mainly deals with commenting the implementation of functions.. Header comments play a different
role. Such comments, usually in the form of line comments that start with an asterisk (*), subdivide large source
codes into meaningful sections and can contain administrative entries. Here the rule also applies that these
comments should not repeat what is already clearly described in the source code or described by any other
means. For example, the person who last changed the program or the change date is indicated in the program
attributes. A header comment with the name of a class or method directly above the class or method is also
redundant information. However, it makes more sense to differentiate between logical program parts, which
cannot be indicated in the code. For example, you can subdivide the program into a global declaration part and
an implementation part. Usually, this is only required if the program is not subdivided by include programs.

3.3.3.3.2 Bad example

The meaning of the comments in the following source code is actually already perfectly obvious due to the
commented statements.

Page: 66 of 227
"Select udat, stime from trdir
"into change_date, change_time
SELECT SINGLE udat, stime
FROM trdir
WHERE name = @prog_name
INTO (@change_date, @change_time).
"Set version_date, version_time to change_date, change_time
IF sy-subrc = 0.
IF change_date > version_date.
version_date = change_date.
version_time = change_time.
ELSEIF change_date = version_date AND
change_time > version_time. version_time =
change_time.
ENDIF.
ENDIF.

3.3.3.3.3 Good example

In the following source code, the comments in the above example have been replaced with a description of why
something happens.

"If a newer program exists, version time stamp must


"be adjusted to program time stamp
SELECT SINGLE udat, stime
FROM trdir
WHERE name = @prog_name
INTO (@change_date, @change_time).
IF sy-subrc = 0.
IF change_date > version_date.
version_date = change_date.
version_time = change_time.
ELSEIF change_date = version_date AND
change_time > version_time.
version_time = change_time.
ENDIF.
ENDIF.

Arrangement in the Source Code

3.3.4.1 Background

The arrangement of comments plays an important role (in addition to comment language and comment content)
in making programs easy to read.

3.3.4.2 Rule

Arrange comments correctly

Place comments in front of the statements that they describe. The horizontal arrangement of comments should
follow the indentations of the source code. End of line comments should only be placed after declarative or
concluding statements.

3.3.4.3 Details

Page: 67 of 227
Vertical positioning
In general, when users read source code, they prefer to view the comment first and then the described
statements. This arrangement means that the correlation between the comment and the associated source
code passage is intuitively clear.

For control structures, this means that comment lines directly before a control statement (such as IF or WHILE)
refer to the associated condition and comment lines after the control statement refer to the associated
statement block. Comment lines directly before an ELSE or WHEN OTHERS statement have obviously been
put in the wrong place.

End of line comments


End of line comments are problematic in conjunction with executable statements. Individual executable program
lines are usually not complex enough to justify a separate comment for each one. If you add end of line
comments, they will often be unwanted repetitions of what the statements clearly indicate already. In addition,
these comments tend to be cryptic and unclear, because the ends of lines does not provide enough space for
meaningful comments in most cases. A uniform alignment for end of line comments can only be achieved with a
high degree of effort.

Therefore, you should make comments for entire statement blocks. Use self-contained comment lines to do
this. This is because it is difficult to describe a reference to more than one statement line if you use end of line
comments.

End of line comments are suitable for the following situations:

• To comment on declarative statements

• To indicate block ends (separate from indentations) in larger control structures

• To justify pseudo comments (at the relevant places) for hiding messages from the extended program
check or Code Inspector.

The pseudo comments for hiding warnings of the extended program check and the Code Inspector play a
special role. They are not comments in the usual sense of the word. They are program directives that must be
appear in the same lines as the commented statements to take full effect. These pseudo comments were
replaced by pragmas for the extended program check.

Indentations
Formatting source code using indentations is essential. Otherwise the human reader cannot understand the
logical structure. This formatting is required by the rule for using the pretty printer. However, if comments are
added in the source code that do not follow this formatting, they hide the logical structure and make the code
difficult to read. Therefore, comment lines must have the same indentation as the statement lines that they
relate to.

These indentations can only be achieved using comments that start with a quotation mark ("), because this
character can be in any position. A comment line that starts with an asterisk (*) must always be in the first
position. It is therefore strongly recommended that you start all comments used in procedures (methods) with a
quotation mark and the correct indentation. Comment lines that start with a quotation mark must not be
confused with end of line comments, which are appear after different code.

Comment lines that start with an asterisk should only be used for head comments of classes and procedures.
Here they help to subdivide a source code into logical sections. In addition, they are useful for temporarily
disabling statements by commenting them out. The commented-out code can be clearly distinguished from
actually indented comments.

3.3.4.3.1 Bad example

Page: 68 of 227
The following source code shows the implementation part of a class. The positioning of the comments does not
follow the above rule.

CLASS application IMPLEMENTATION. "Application class


METHOD main. "Main Method
* Item data
DATA items TYPE STANDARD TABLE
OF REF TO item.
DATA item_ref LIKE LINE OF items.
* Amount data DATA amount TYPE i.
DATA total_amount TYPE i.
...
* Loop over all items to compute total amount
LOOP AT items INTO item_ref. "Loop over all items
IF item_ref IS BOUND AND
item_ref->is_valid( ) = abap_true. "Check validity
amount = item_ref->get_amount( ). "Get amount
ADD amount TO total_amount. "Add amount to totals
... "...
ELSE.
...
ENDIF.
ENDLOOP.
...
ENDMETHOD.
ENDCLASS.

3.3.4.3.2 Good example

The following source code shows the same implementation part as above. However, the comments are
positioned as recommended. Comment lines that start with an asterisk (*) are used as header comments in the
program structure. End of line comments only appear after declarations and block ends. All other comments
appear in comment lines before the described statements and are indented accordingly.

*----------------------------------------------------------*
* Class implementations
*
*----------------------------------------------------------*
CLASS application IMPLEMENTATION.
*----------------------------------------------------------*
METHOD main.
DATA: items TYPE STANDARD TABLE
OF REF TO item, "Item table
item_ref LIKE LINE OF items. "Item reference
DATA: amount TYPE i, "Amount per item
total_amount TYPE i. "Total amount of items
...
"Loop over all items to compute total
amount LOOP AT items INTO item_ref. IF
item_ref IS BOUND AND item_ref-
>is_valid( ) = abap_true. "Compute total
amount for valid items amount =
item_ref->get_amount( ).
ADD amount TO total_amount.
...
ELSE.
ENDIF. "item_ref IS BOUND AND...

Page: 69 of 227
ENDLOOP.
...
ENDMETHOD. "main
*----------------------------------------------------------*
ENDCLASS. "application

3.4 Program and Procedure Structure


ABAP offers you a great deal of freedom when structuring your programs and procedures. Remember, however,
that the finished product needs to be easy to maintain.
Global Declarations of a Program

3.4.1.1 Background

Each ABAP program has a global declaration part where you can declare data types, interfaces, classes, and
data objects that are visible throughout the program.

From a technical viewpoint, the global declaration part consists of all declarations that cannot be assigned to a
more local context (class, procedure). All declarations implemented in processing blocks without their own
contexts (in event blocks and dialog modules) and declarations declared between completed processing blocks
are assigned to the global context. Event blocks of GET and AT SELECTION-SCREEN events are exceptions.
Variables declared here are only valid in the event block.

In an ABAP statement, you can only ever refer to the previous declarations of the currently visible contexts.

3.4.1.2 Rule

Implement global declarations centrally

Place the global declaration part of a program at a central, context-related point at the beginning of the
program.

3.4.1.3 Details

You should only use the area between the introductory statement of an ABAP program and the first
implementation as the global declaration part. This the only place where you should implement global
declarations in a meaningful sequence. This ensures that the declarations intended for global use can really be
used in all subsequent implementations.

There should not be any declarative statements in contexts that do not support local data (provided that they
are still used). Otherwise, a false impression of local validity is created when the program is read, which may
lead to the program not being correctly understood.

You only need to deal with this rule explicitly if you work with program types other than class or interface pools.
The Class Builder implicitly specifies which declarations occur and where. These are the declarations of the
global class/global interface itself as well as optional local data types, classes, and interfaces in class pools.
The developer cannot directly access the main program of a class pool or interface pool. This is still the case
even if the source-code-based Class Builder is introduced, because it only shows the declaration and
implementation of the global class.

For other program types (subroutine pools, function groups, and executable programs), the developer can
access the entire main program. If you work with these program types, you must ensure that the rule is adhered
to yourself. The top include can help you do this. It is especially suited to all programs that are organized using

Page: 70 of 227
include programs. The top include is specially designed for the global declaration part and is therefore
supported by the ABAP Workbench and ABAP Compiler. The ABAP Workbench enables you to automatically
create and integrate the top include. The Compiler incorporates the relevant top include into the syntax check
for an individual include program. This enables you to perform meaningful syntax checks of individual include
programs.

If the top include is available, it should always be the first include program that a main program incorporates.
The top include can also contain additional INCLUDE statements. The top include, and any include programs
incorporated in the top include, can only contain declarations and not implementations.

If you mainly work with ABAP objects, the global declaration part or the top include should only contain
declarations of local classes and interfaces, if the above rule is strictly adhered to. Data types should only be
declared for classes and interfaces or in the ABAP Dictionary. Global data objects are only required for
communication with classical dynpros. Therefore they should only be used in the top include for function groups
that encapsulate classical dynpros. 3.4.1.3.1 Exception
The above rule can be mainly justified due to the visibility within the program and the validity of declarations.
Strictly speaking therefore, it only applies to program types other than class pools. In class pools, the visibility
outside of the class pool and the resulting dependencies are also important.

A further exception occurs in the following situation: the local classes of a program are relatively independent
units and their implementations do not refer to the declarations of other local classes. In this case, you can list
your declaration and implementation parts one after the other to improve readability.

3.4.1.3.2 Bad example

The following source text shows a function group for encapsulating a classical dynpro, after the include
programs have been resolved. The two dialog modules contain data declarations that look like local
declarations but have global validity. You can only statically access this type of data object below the
declaration, so that the function module has no access to g_input_field, and the PBO module has no access to
g_ok_code.

FUNCTION-POOL z_screen.
DATA g_start_value TYPE c LENGTH 20.
FUNCTION z_handle_screen.
*"------------------------------------------------------
*"*"Local Interface:
*" IMPORTING
*" REFERENCE(i_start_value) TYPE csequence OPTIONAL
*"------------------------------------------------------
g_start_value = i_start_value.
CALL SCREEN 100.
ENDFUNCTION.
MODULE status_0100 OUTPUT.
DATA g_input_field TYPE c LENGTH 20.
g_input_field = g_start_value.
ENDMODULE.
MODULE user_command_0100 INPUT.
DATA g_ok_code TYPE sy-ucomm.
CASE g_ok_code.
WHEN '...'.
...
ENDCASE.
ENDMODULE.

3.4.1.3.3 Good example

Page: 71 of 227
The following source code shows the function group from the above example, after the global declarations have
been moved to a coherent global declaration part that follows the introductory statement. The additional global
data object g_start_value is no longer required, and you can access g_ok_code in the PBO module.

FUNCTION-POOL z_screen.
DATA: g_input_field TYPE c LENGTH 20,
g_ok_code TYPE sy-ucomm.
FUNCTION z_handle_screen.
*"------------------------------------------------------
*"*"Local Interface:
*" IMPORTING
*" REFERENCE(i_start_value) TYPE csequence OPTIONAL
*"------------------------------------------------------
g_input_field = i_start_value.
CALL SCREEN 100.
ENDFUNCTION.
MODULE status_0100 OUTPUT.
CLEAR g_ok_code.
ENDMODULE.
MODULE user_command_0100 INPUT.
CASE g_ok_code.
WHEN '...'.
...
ENDCASE.
ENDMODULE.

Local Declarations

3.4.2.1 Background

Local declarations can be made in a procedure ( method). These are data types, data objects, and field
symbols that are valid in the context of the procedure only. Therefore, they can only be addressed in the code of
the procedure and are only available during the execution of the procedure (the data objects declared with
STATICS are an exception).

Procedure-local declarations can be listed at any position of a procedure. However, the position of the
declaration does not influence the validity area of the declared object (which always comprises the entire
procedure), but only the static visibility.

3.4.2.2 Rule

Implement local declarations at the beginning of the procedure

Position the local declarations of a procedure ( method coherently and at the beginning of a procedure. The
local declarations must not be distributed across the implementation of the procedure.

3.4.2.3 Details

Local declarations within a procedure ( method) are statically visible starting from the point of the program
where they are positioned to the end of the procedure. However, because they are valid in the entire procedure,
the declared entities can be accessed dynamically throughout the entire procedure. The following program
example illustrates the different behavior:

Page: 72 of 227
METHOD demo_method.
FIELD-SYMBOLS <field_symbol> TYPE any.
...
* ASSIGN dobj TO <field_symbol>. "Syntax error ...
ASSIGN ('DOBJ') TO <field_symbol>. "No error
ASSERT <field_symbol> IS ASSIGNED.
...
DATA dobj TYPE i.
ENDMETHOD.

Because the different behavior of the dynamic and the static variant of the ASSIGN statement is rather
unexpected, all declarations are supposed to be carried out at the beginning of the procedure, that is, between
the introductory and the first executable statement. Then, the static and the dynamic visibility sections match.
This rule contradicts the common recommendations for other programming languages. They recommend
declaring local variables as close to their use as possible to tightly restrict their validity area. In ABAP, however,
there is no block-local validity of local variables. Positioning a declaration within the statement block of a loop,
for example, does not make it possible to restrict the validity of this declaration to this statement block. Rather,
the variable is valid within the entire procedure. So a declaration at the position where it is used can be
misleading to developers or readers of a program who are not aware of this.

According to the rule, the size of a procedure should be selected in such a way that the procedure remains
clear for the reader, which means there is no good reason why all variables should not be declared as a whole
at the beginning of a procedure.

3.4.2.3.1 Note

Within processing blocks that do not support any local data (dialog modules and event blocks), declarative
statements must be omitted completely.

In function modules and subroutines, there should be no local data, only a method call.

3.4.2.3.2 Exception

Inline declarations in procedures generally represent an exception. If used correctly, they can make a program
easier to understand.

3.4.2.3.3 Bad example

The following source code shows a local data declaration in a loop. Readers who are familiar with another
programming language or even the developer of the program himself would probably expect the number
variable to be set to value 10 for each loop pass. Indeed, number is set to 10 exactly once when the method
starts because the variable is generated only once for the context of the method and provided with a start value.

METHOD main.
...
DO 10 TIMES.
DATA number TYPE i VALUE 10.
...
"number = 11, 13, 16, 20, ...
number = number + sy-index.
...
ENDDO.
...
ENDMETHOD.

3.4.2.3.4 Good example

Page: 73 of 227
The following source code shows the corrected version of the above example, which behaves as the above
example is expected to behave (if deeper ABAP knowledge is not involved). There is no block-local validity of
data in ABAP, so proceed as shown below.

METHOD main.
DATA number TYPE i.
...
DO 10 TIMES.
number = 10.
...
"number = 11, 12, 13, 14, ...
number = number + sy-index.
...
ENDDO.
...
ENDMETHOD.

3.5 Source Code Organization


ABAP source code is saved in the ABAP Repository in the central database of an AS ABAP, and not in source
code files like in most other programming environments. Source codes can be split into individual units by using
include programs. There are also macros that are handled for callable modularization units in the context of
these guidelines.

Source code modularization

3.5.1.1 Background

The unit in the ABAP environment that corresponds to a source code file capable of being inserted into another
program is known as an include program. Include programs are used for source code modularization and are
inserted into master programs for this purpose. Include programs are not compilation units (which means they
are not compilable on their own), but can be activated and transported separately. The master programs of
include programs (such as class pools, interface pools, function groups, subroutine pools, or executable
programs) are compilation units in which, when compiled, an INCLUDE statement is replaced by the content of
the specified include program.

3.5.1.2 Rule

Use include programs to modularize source code.

Distribute the source code of large ABAP programs across several include programs, remembering to choose a
granularity for the modules that suits the structure of the program's structure.

3.5.1.3 Details

A suitable level of source code modularization using include programs makes it easier to develop and modify
larger programs in several ways:

• The lock management of ABAP Editor works at the level of include programs. In this way, several
developers can make changes to a large program at the same time, as long as the source code
sections in question are in different include programs.

Page: 74 of 227
• Include programs are activated separately. This means that corrections or new developments in a
master program can be activated independently of each other, as long as they are in separate include
programs.

• Include programs can be transported separately. In this way, specific corrections can be distributed
across a system landscape without the need to transport the entire master program. This minimizes the
potential for conflicts between correction levels.

The development environment already provides modularization templates using includes for many master
programs. For example, the visibility sections and methods of global classes or function modules of a function
group are saved in separate include programs. The source code-based Class Builder displays the resolved
include programs as a single programs, but saves each part separately. The top include for global declarations
is also supported by ABAP Workbench and ABAP Compiler.
As well as this, you can perform manual modularization using include programs, if required. Here, you can
perform some of the extra modularizations on the include programs defined by ABAP Workbench. Or you can
create include programs for master programs that are not modularized automatically (such as subroutine pools
and executable programs).

Include programs that you create manually must contain a logically related section of the source code and this
section must represent an independently maintainable and transportable unit. Logically related units such as
individual procedures (methods) or the declaration parts of local classes should not be distributed across
multiple include programs, however. (The declaration parts of global classes are distributed automatically
across multiple include programs, as specified by ABAP Compiler. There is no reason why ABAP developers
should distribute local classes in the same way.)

Include programs you create manually should be named in accordance with the naming conventions of ABAP
Workbench for automatically generated include programs. These conventions emphasize the relationship
between the include program and the master program and prevent include programs from being used more
than once

Multiple use of include programs

3.5.2.1 Background

From a technical point of view, it is possible to use an include program multiple times by integrating it more than
once into a master program or different master programs.

3.5.2.2 Rule

Do not use include programs more than once

Use an include program for the modularization of exactly one master program. It must not be integrated into
multiple different master programs. Also, an include program should only be integrated once within a master
program.

3.5.2.3 Details

The multiple use of include programs is highly problematic conceptually. This particularly concerns the use of
include programs for the reuse of:

• Type definitions

Page: 75 of 227
• Data declarations

• Local classes

• Procedure implementations

We strongly recommended using only suitable means for reuse, such as global classes or interfaces, for the
reasons specified in the following sections.

Restricted maintainability
The integration of an include program into several master programs dramatically restricts the maintainability
both of the include program itself and of the master programs using it. Changes to such an include program can
be unproblematic in the context of selected master programs, but can make other master programs
syntactically incorrect at the same time. This is particularly critical for master programs that integrate include
programs that were developed in other systems.

Increased resource consumption


If master programs that use shared include programs are executed at the same time, these include programs
must be loaded multiple times by the ABAP runtime environment, which increases memory consumption. In the
past, include programs were used multiple times for the central definition of constants, for example. Today, you
should use a global interface or global class for this purpose. Because it is loaded only once, the memory
consumption does not increase with every new use as it does with any multiple use of include programs.

The memory consumption also increases if an include program is used multiple times within one master
program (for example, through integration into the source code of multiple function modules of a function group
or into the source code of multiple methods of a class) because this expands the master program
unnecessarily. When using centrally defined, standalone types and storing required constants in suitable
classes or interfaces, there remains no conceivable scenario where it would be useful to use include programs
multiple times within a master program.

Missing semantic context


Like source code files in other programming environments, include programs are integrated into a master
program as pure text and without any semantics. The semantics only emerge in the context of the master
program and the position where the include program is integrated. Consequently, especially class definitions
that are integrated into different master programs by using an include program result in different technical
classes whose objects have different reference types and cannot be exchanged between the master programs.

3.5.2.3.1 Bad example

The following source code shows an include program that contains declarations of constants intended for use in
multiple programs. According to the above rule, such a procedure is no longer permitted.

*&---------------------------------------------*
*& Include Z_ORDERS_OF_MAGNITUDE
*&---------------------------------------------*
CONSTANTS:
mega TYPE p DECIMALS 6 VALUE
'1000000.0', kilo TYPE p DECIMALS 6 VALUE
'1000.0', milli TYPE p DECIMALS 6 VALUE
'0.001', micro TYPE p DECIMALS 6 VALUE
'0.000001'.

3.5.2.3.2 Good example

The following source code shows the same declarations of constants as in the above example, but this time in a
global class suitable for reuse. Here, a corresponding ABAP Unit test method would even be possible that
checks the consistency of the constants.

Page: 76 of 227
CLASS zcl_orders_of_magnitude DEFINITION PUBLIC .
PUBLIC SECTION.
CONSTANTS: mega TYPE p DECIMALS 6
VALUE '1000000.0', kilo TYPE p DECIMALS 6
VALUE '1000.0', milli TYPE p DECIMALS 6
VALUE '0.001', micro TYPE p DECIMALS 6
VALUE '0.000001'. ENDCLASS.

3.6 Alternative Spellings


Some ABAP statements can be written with different spellings, but interpreted by the compiler in the same way.
To make programming easier to understand, however, spellings should be kept the same, with alternative
spelling used only in special situations.

Alternative Language Constructs

3.6.1.1 Background

Alternative language constructs are parts of statements that can be written in different ways. One reason for this
are the constant new developments in the language. Often, new spellings are introduced and the old spellings
retained for reasons of downward-compatibility.

3.6.1.2 Rule

Using consistent spelling

If there is more than one spelling for a statement, choose one of these spellings and use it consistently
throughout your development work It is best to choose the spelling that most accurately reflects the semantics
of the statement.

3.6.1.3 Details

To make your programming easier to understand, always choose the spelling that is most accurate and easiest
to read, and which (where applicable) matches the spelling used in other statements. The following list contains
some examples:

• If you can choose from a range of comparison operators (= or EQ, > or GT, < or LT, >= or GE, <= or
LE) we recommend that you pick a type of operator and stick to it within the context of a program. The
variant with the characters =, <, and > is seen as more modern, but also overloads these characters.
The relational operators that consist of two letters are better matched to other relational operators such
as CO, CN, and so on, which have no alternative forms.

• The addition NOT of the relational operators BETWEEN, IN, IS ASSIGNED, IS BOUND, IS INITIAL,
and IS SUPPLIED is a better option than the identical boolean operator NOT, for improved readability.
For example, the expression a IS NOT INITIAL is easier than the logically identical expression NOT a
IS INITIAL. This corresponds to the definition of comparison expressions, where a <> b is more intuitive
than NOT a = b.

• The addition LENGTH len of the declarative statements DATA and TYPES is preferable to the length
specified in parentheses (len). This then matches the spelling used in CREATE DATA ... LENGTH. In
addition to this, it is easy to mistake the parenthesized form for dynamic tokens. Only dynamic tokens
should use this form.

Page: 77 of 227
• The optional addition SUBSTRING of the statements FIND and REPLACE can be used to make a
clearer distinction from the alternative addition REGEX.

• In Open SQL, comma-separated lists are preferable to lists without commas. Using commas as
separators is the prerequisite for using expressions in lists. Host variables should always be indicated
by the escape character @.
• Within the parameter list of the statements EXPORT and IMPORT, use the equals sign (=) instead of
the additions FROM or TO. The spelling then matches the spelling used in parameter lists in other
calls, such as methods, functions modules, and transformations.

• Always use the semantically identical addition ACTUAL LENGTH instead of the addition LENGTH of
the statement READ DATASET. This makes the distinction from the similar addition MAXIMUM
LENGTH clearer. The last two examples are typical of the way new additions are added to the
language, while retaining the old spelling (in a shortened form) for reasons of downward compatibility.

3.6.1.3.1 Bad example

The following piece of source code shows how the statement FIND is used inconsistently within a program. The
first and third FIND statements are alternative spellings with the same meaning.

DATA text TYPE string.


...
FIND '...' IN text.
...
FIND REGEX '...' IN text.
...
FIND SUBSTRING '...' IN text.
...

3.6.1.3.2 Good example

The following piece of source code shows the same statements as in the example above, but with consistent
spelling. This expresses the semantic distinction between searching for a substring and searching for a regular
expression in clear syntax.

DATA text TYPE string.


...
FIND SUBSTRING '...' IN text.
...
FIND REGEX '...' IN text.
...
FIND SUBSTRING '...' IN text.
...

Chained Statements

3.6.2.1 Background

Successive ABAP statements that have the same starting part can be expressed in a chained statement. A
chained statement consists of the identical starting part that is specified once and that is concluded by a colon
(:). Behind this colon, the remaining parts are separated by commas (,). Only the last part is concluded with a
period (.). During the syntax check and the compilation, a chained statement is handled like the respective
sequence of individual ABAP statements, where the shared starting part is put in front of each remaining part.
The identical starting parts are not restricted to the key word.

Page: 78 of 227
3.6.2.2 Rule

Only use chained statements where appropriate

Use chained statements mainly for declarations. They should always be used for related declarations of type
TYPES BEGIN OF ... TYPES END OF ....
3.6.2.3 Details

The main motivation for using chained statements is to increase the readability of programs. Using chained
statements correctly in declarations achieves this goal. In other statements, chained statements can actually
decrease the readability or, in the worst case, result in incorrect program behavior. When using chained
statements, only one statement at most should be specified per program line. Never span expressions or
functional calls across multiple parts of chained statements.

3.6.2.3.1 Declarations

In complex declarations, chained statements can be used to improve readability. (However, if local declarations
are too complex, this suggests an insufficient separation of tasks, and should not occur.) In particular, multiple
chained statements can be used to group related declarations:

DATA:
airplane TYPE REF TO cl_airplane,
airplane_attributes TYPE cl_airplane=>airplane_attributes.
DATA:
airport TYPE REF TO cl_airport,
airport_attributes TYPE cl_airport=>airport_attributes.
...

The grouping of declarative statements that semantically represent a composite statement is even more
important. For example, the declaration of structured types and data objects in ABAP is done using individual
statements, whose close relationship should be expressed by a chained statement:

TYPES:
BEGIN OF file, name TYPE
string, owner TYPE sy-uname,
creation_date TYPE timestamp,
END OF file.

For structures that copy components of another structure using the statements INCLUDE TYPE or INCLUDE
STRUCTURE, this procedure cannot be used consistently because the beginning of the statement is different
and therefore the chained statement must be interrupted. In any case, we no longer recommend using the
statement INCLUDE.

3.6.2.3.2 Operational Statements

For operational statements, however, chained statements are not recommended because they do not usually
result in better readability. Example:

CALL METHOD meth EXPORTING para = : '1', '2', '3'.

Here, the exploitation of the fact that the same starting parts in front of the colon are not limited to the keyword
was a little overdone. The following chained statement would be easier to read:

CALL METHOD:

Page: 79 of 227
meth EXPORTING para = '1',
meth EXPORTING para = '2',
meth EXPORTING para = '3'.

However, in this case the best notation can manage without a chained statement anyway:
meth( '1' ). meth(
'2' ). meth( '3' ).

3.6.2.3.3 Unexpected Behavior

If chained statements are not understood correctly, this can easily result in the creation of syntactically correct
statements with unexpected behavior. Prominent examples are introductory statements within control
structures. Here, the use of chained statements does not usually lead to the intended result.

Let us look at the following TRY control structure, in which the CATCH statements are implemented using a
chained statement:

TRY.
...
CATCH: cx_1, cx_2, cx_3.
"exception handling
...
ENDTRY.

A reader and probably even a developer would assume that this is a CATCH block that handles three
exceptions. In fact, the complete syntax is as follows:

TRY.
...
CATCH cx_1.
CATCH cx_2.
CATCH cx_3.
"exception handling
...
ENDTRY.

The cx_1 and cx_2 exceptions are indeed caught, but the corresponding CATCH blocks are empty. Only the
third exception cx_3 has a CATCH block that is not empty. The syntax that the developer presumably intended
is as follows:

TRY.
...
CATCH cx_1 cx_2 cx_3.
"exception handling
...
ENDTRY.

For the WHEN blocks within a CASE control structure, the following applies:

WHEN: a, b, c. is not

equivalent to the more probable

WHEN a OR b OR c.

Page: 80 of 227
The extended program check warns of empty statement blocks after CATCH and WHEN. In this way, the
extended program check can be used to uncover where chained statements have been misused within TRY
and CASE control structures.

Another example in which the use of chained statements can cause problems are Open SQL statements. Here
are two examples:
• The following chained statement consists of two SELECT statements that both supply a work area with
values, and of which only the second one has a WHERE condition.

SELECT SINGLE carrid, connid


FROM spfli
WHERE @carrid = '...'
INTO: @carrid_wa, @connid_wa.

The following INTO clause was undoubtedly meant here:

INTO (@carrid_wa, @connid_wa).

• In the following example, the seemingly single statement does not update the discount and the
telephone number of the customer with the customer ID 00017777. Instead, these are in fact two
statements, of which the first changes the discount for all customers and the second changes the
telephone number of the customer with the customer ID 00017777.

UPDATE scustom SET: discount = '003',


telephone = '0621/444444' WHERE id
= '00017777'.

Even if the previous examples of the chained statements would show the semantic that is expected by the
developer, such use is not recommended in any case because each reader would probably expect a different
program behavior, and the readability and maintainability of the source code would be impaired considerably.

3.6.2.3.4 Expressions and Function Calls

Unfortunately, ABAP statements can be spanned across the colon in chained statements, even within
expressions or function calls. The following example with correct syntax shows what can happen here, even in
the simplest of cases. This example cannot be understood and nor does it produce the expected result.

DATA: itab TYPE TABLE OF i,


num TYPE i.

itab = VALUE #(: ( 1 ) ), ( 2 ) ), ( 3 ) ), ( 4 ) ).


num = itab[: 1 ], 2 ], 3 ], 4 ].

cl_demo_output=>new(
)->write_data(: `Text1` ), `Text2` ), num )-
>display( ).

Method Calls

3.6.3.1 Background

Static calls of methods can be formulated in two different ways. The obsolete long form

CALL METHOD meth EXPORTING ...

Page: 81 of 227
is based on the notation of the function module call. Alternatively, a short form can be used:

meth( ... ).
This form uses a parenthesis notation instead of the introductory ABAP words CALL METHOD. A
combination of CALL METHOD and parentheses is also possible.
3.6.3.2 Rule

Formulate static method calls without CALL METHOD

Use the long form of the method call using CALL METHOD only for dynamic method calls.

3.6.3.3 Details

The short form of the static method call is clearer. The redundant ABAP words CALL METHOD provide no
additional information to the reader. Using the short form, self-contained method calls have the same
appearance as functional method calls on operand positions. For dynamic method calls, the long form with
CALL METHOD is syntactically necessary. If it is only used there, the different notations provide the reader with
another distinguishing feature between the static and dynamic method call.

3.6.3.3.1 Bad example

The following source code shows the long form of a static method call using CALL METHOD, which is no longer
recommended.

...
CALL METHOD cl_class=>do_something
EXPORTING
some_input = value1
IMPORTING
some_output = value2
CHANGING
some_change = value3.
...

The following source code shows the same static method call as above, but with parentheses inserted. In this
form, which is also syntactically correct, either CALL METHOD or the parentheses are superfluous.

...
CALL METHOD cl_class=>do_something(
EXPORTING
some_input = value1
IMPORTING
some_output = value2
CHANGING
some_change = value3 ).
...

3.6.3.3.2 Good example

The following source code shows the same method call as above, but as recommended, without CALL
METHOD. If a method has only importing parameters, IMPORTING and CHANGING can be omitted, and also
the EXPORTING addition. If it is a single importing parameter, its name can also be omitted.

...
cl_class=>do_something( EXPORTIN
G

Page: 82 of 227
some_input = value1
IMPORTING
some_output = value2
CHANGING
some_change = value3 ).
...

Assignments

3.6.4.1 Background

For explicit assignments in which the value of a source is assigned to a target, ABAP contains the general
assignment operator = and the special casting operator ?=. Statements with these operators

lhs =|?= rhs.

enable assignments of

• data objects,

• Return values/results of functional methods, predefined functions, or construction expressions, table


expressions and

• results of calculation expressions (arithmetic expressions, bit expressions, and string expressions) to

variables that can also be declared inline and to writable expressions.

Alongside the assignment operators, two obsolete statements exist for historical reasons that can also perform
assignments:

• The statement

MOVE source TO|?TO destination.


assigns a source source to a target destination. It covers some of the operators performed by the
assignment operators = and ?=.

• The statement

COMPUTE lhs =|?= rhs.


has the same semantics as lhs =|?= rhs. The keyword COMPUTE can be written in front of each
assignment with the assignment operators = and ?= where the left side is not an inline declaration, but
is ignored.

3.6.4.2 Rule

Assignments with the assignment operators = and ?= only

Use the assignment operators instead of the statement MOVE. Do not use the keyword COMPUTE in front of
assignments.

3.6.4.3 Details

Page: 83 of 227
Assignments with the assignment operators = and ?= implement the most global concept. The right side is a
general expression position and the left side is a declaration position (except in down casts).

The statements MOVE and COMPUTE have the following drawbacks:


• The statement MOVE cannot be used globally. The only sources allowed are data objects, function
methods, and certain predefined functions whose arguments must be single data objects. The only
targets allowed are variables; inline declarations are not possible. Any future enhancements to operand
positions will not be applied to MOVE.

• The keyword COMPUTE is both confusing and surplus to requirements. If an arithmetic expression or
other calculation expression is on the right side, the keyword COMPUTE has the correct meaning, but
is redundant. If a data object, a function method, a predefined functions, or a constructor expression is
on the right side, the keyword COMPUTE has the wrong meaning, since a return value is assigned
instead of an expression being calculated.

The statements MOVE and COMPUTE were created at a time when assignments were only made between
individual data objects and calculations were exclusively arithmetic. Neither of these statements is appropriate
in a modern, expression-oriented ABAP program that exploits all options on the left and right sides of an
assignments.

3.6.4.3.1 Note

The optional addition EXACT of the statements MOVE and COMPUTE, which produces lossless assignments
and lossless calculations, has been replaced in full by the lossless operator EXACT.

3.6.4.3.2 Bad example

The following source code shows a simple assignment using MOVE and the assignment of an arithmetic
expression after COMPUTE.

DATA text1 TYPE string.


DATA text2 TYPE string.
...
MOVE text1 TO text2.

DATA result TYPE decfloat34.


DATA number1 TYPE i.
DATA number2 TYPE i.
...
COMPUTE result = number1 * number2.

3.6.4.3.3 Good example

The following source code shows the same example as above but without specifying the keywords MOVE and
COMPUTE. This makes inline declarations possible on the left side.

DATA text1 TYPE string.


...
DATA(text2) = text1.

DATA number1 TYPE i.


DATA number2 TYPE i.
...
DATA(result) = CONV decfloat34( number1 * number2 ).

Page: 84 of 227
Calculations

3.6.5.1 Background

In ABAP, the arithmetic operators in arithmetic expressions are used for numeric calculations. Alongside the
operand format, the dedicated ABAP keywords ADD, SUBTRACT, MULTIPLY and DIVIDE are also used for the
basic arithmetic operations.

3.6.5.2 Rule

Using Operator Format

For calculations, use the operator format with the equals sign (=) instead of the ABAP keyword format.

3.6.5.3 Details

Calculations with the statements ADD, SUBTRACT, MULTIPLY, and DIVIDE are often more difficult to read than
the corresponding operator format. Calculations other than the basic arithmetic operations cannot be expressed
by ABAP keywords in any case.

3.6.5.3.1 Exception

The command format allows the use of chained statements, which can be useful in these special cases:

ADD increment TO: sum_individual,


sum_total.

If arithmetic operations are in the form a = a + 1, where the target variable and one of the operands are
identical, using the statements ADD, SUBTRACT and so on has the advantage of being easier on the eye,
especially when the name of the target variable is relatively long:

SUBTRACT 1 FROM reference->structured_attribute-component.

It is immediately clear to the observer that the value of the specified variables is reduced by one. This may not
be the case for the operator format, if it is not straightaway obvious that the target variable and one of the
operands are identical. In such cases you can and should ignore the above rule. The primary concern is the
readability of the source code.

3.6.5.3.2 Bad example

The following source code shows a multiplication using the statement MULTIPLY.

MULTIPLY n1 by n2.

3.6.5.3.3 Good example

The following source code shows the same example as above, but in the more compact operator format.

n1 = n1 * n2.

Page: 85 of 227
3.7 Complexity
The aim of program complexity is to keep the source code as clear and readable as possible for the human
reader. The computer has no problems with compiling or executing highly complex programs. Unformatted
source code does also not constitute any problems. The human reader, however, is usually overwhelmed by the
program complexity.

High complexity in this context means, for example, voluminous procedures (methods) and control structures
with a very deep nesting or unclear classes without clearly defined tasks. The program complexity must not be
confused with the complexity of the task that is handled by the program. Even if task complexity is very high, it
is always possible to keep the program complexity manageable for individual procedures and classes by clearly
separating the tasks.

To understand a program, the reader must be able to mentally trace the flow, and keep an eye on the different
paths through the program that result from the control structure, under different external conditions. This is very
difficult when dealing with voluminous procedures or deep nesting. In these situations, the program author may
have been overwhelmed and consequently the program might contain errors. These situations increase the
time required for corrections or further developments and the risk of errors. What makes the situation even
more difficult is that testing complex procedures requires a great deal of time and effort, due to the high number
of possible execution paths. Formulating a test case for every single execution path is often impossible due to
the high number of paths.

Expressions

3.7.1.1 Background

An expression is part of an ABAP statement that returns a result. An expression consists of one or more
operands in combination with operators or special ABAP words. Expressions can be logical expressions
constructed from relational expressions and also calculation expressions. The latter type is subdivided into
arithmetic expressions, bit expressions, and character string expressions. Data objects, other suitable
expressions, and calls for built-in functions and functional methods can all be used as expression operands. In
character string processing, regular expressions for searches and pattern comparisons are also used.

These expressions can be nested and combined in many different ways. Nested and chained calls are possible
for functional methods. The maximum nesting depth of expressions is restricted to 32 by the ABAP Compiler.

3.7.1.2 Rule

Limit the complexity of expressions

Use expressions at operand positions in a way that means the program remains legible and understandable.

3.7.1.3 Details

The diverse options for expressions mean that the use of helper variables is superfluous in many places. The
use of expressions and functional calls at operand positions is useful under the following prerequisites:

• The result of an expression or a calculation is required only once. If an intermediate result is required
multiple times, it should only be calculated once and saved in a helper variable. (The ABAP Compiler
does not implicitly handle this task at the moment)

• The data type of the result matches the operand position, or the conversion rules for an expression/call
used at an operand position are suitable for the task to be implemented. If special type conversions

Page: 86 of 227
must be performed, for example, for date or time fields, helper variables of an appropriate type might
be required.
Programs should always be kept clear and legible.. Do not be too ambitious and combine everything into one
single expression. If an expression becomes too complex, it should be split at suitable points, and the
intermediate results should be saved in helper variables. This particularly applies to character string processing
with character string templates and to regular expressions. These are very powerful but they can also make
programs difficult to read very quickly. Comments can also help to describe the way a complex expression
works.

3.7.1.3.1 Bad example

The following source code shows an arithmetic expression in a relational expression in a loop. The same total
must be recalculated for each loop pass.

LOOP AT itab ASSIGNING <wa>.


IF oref->meth( <wa> ) < sy-tabix * ( offset + length ).
...
ENDIF.
ENDLOOP.

3.7.1.3.2 Good example

The following source code has the same function as the example above. However, the total is only calculated
once before the loop.

limit = offset + length.


LOOP AT itab ASSIGNING <wa>.
IF oref->meth( <wa> ) < sy-tabix * limit.
...
ENDIF.
ENDLOOP.

Nesting Depth

3.7.2.1 Background

An expression is part of an ABAP statement that returns a result. An expression consists of one or more
operands in combination with operators or special ABAP words. Expressions can be logical expressions
constructed from relational expressions and also calculation expressions. The latter type is subdivided into
arithmetic expressions, bit expressions, and character string expressions. Data objects, other suitable
expressions, and calls for built-in functions and functional methods can all be used as expression operands. In
character string processing, regular expressions for searches and pattern comparisons are also used.

These expressions can be nested and combined in many different ways. Nested and chained calls are possible
for functional methods. The maximum nesting depth of expressions is restricted to 32 by the ABAP Compiler.

3.7.2.2 Rule

Limit the complexity of expressions

Use expressions at operand positions in a way that means the program remains legible and understandable.

3.7.2.3 Details

Page: 87 of 227
The diverse options for expressions mean that the use of helper variables is superfluous in many places. The
use of expressions and functional calls at operand positions is useful under the following prerequisites:
• The result of an expression or a calculation is required only once. If an intermediate result is required
multiple times, it should only be calculated once and saved in a helper variable. (The ABAP Compiler
does not implicitly handle this task at the moment)

• The data type of the result matches the operand position, or the conversion rules for an expression/call
used at an operand position are suitable for the task to be implemented. If special type conversions
must be performed, for example, for date or time fields, helper variables of an appropriate type might
be required.

Programs should always be kept clear and legible.. Do not be too ambitious and combine everything into one
single expression. If an expression becomes too complex, it should be split at suitable points, and the
intermediate results should be saved in helper variables. This particularly applies to character string processing
with character string templates and to regular expressions. These are very powerful but they can also make
programs difficult to read very quickly. Comments can also help to describe the way a complex expression
works.

3.7.2.3.1 Bad example

The following source code shows an arithmetic expression in a relational expression in a loop. The same total
must be recalculated for each loop pass.

LOOP AT itab ASSIGNING <wa>.


IF oref->meth( <wa> ) < sy-tabix * ( offset + length ).
...
ENDIF.
ENDLOOP.

3.7.2.3.2 Good example

The following source code has the same function as the example above. However, the total is only calculated
once before the loop.

limit = offset + length.


LOOP AT itab ASSIGNING <wa>.
IF oref->meth( <wa> ) < sy-tabix * limit.
...
ENDIF.
ENDLOOP.

Procedure Volume

3.7.3.1 Background

The procedure volume is the number of executable ABAP statements in a procedure (method). In theory, this
number has no upper limit and is only limited by the maximum program size that fits into the current program
memory.

3.7.3.2 Rule

Restrict the number of statements in procedures

Page: 88 of 227
Restrict the number of executable ABAP statements in a procedure (method) to a manageable size. A maximum
of 150 executable statements per procedure is the recommended guideline.
3.7.3.3 Details

Procedures with large volumes (methods) generally have a complex decision structure, a lot of procedure
parameters and work with a multitude of local data. These procedures, which often do not perform a clearly
defined single task, are difficult to understand and therefore particularly prone to errors. You should use several
small procedures with narrow interfaces and closely defined tasks. The ideal parameter interface has a small
number of input parameters and only one return value.

The number of executable statements is a simple measure of the complexity of a procedure. All statements that
are not declarations and do not define processing blocks can be regarded as executable statements. This is
very similar to statements at which program execution can be stopped in the debugger. Procedure-concluding
statements, such as ENDMETHOD, at which you can stop in the debugger are exceptions. However, these are
not regarded as executable statements.

3.7.3.3.1 Note

The recommendation not to write procedures that are too large should not lead to the other extreme (too many
procedures that are very small). Procedures should be of a reasonable size that is consistent with the ABAP
programming language (modularize instead of atomize).

3.7.3.3.2 Exception

Strict linear code (for example, programmatic filling of a table with single values) cannot be subdivided into
multiple procedures. In these cases, a restriction on the number of statements does not make sense.

3.7.3.3.3 Example

See the KISS Principle figure.

Class Size

3.7.4.1 Background

The class size is the number of components (attributes, methods, events) of a class. The ABAP Compiler
predefines a maximum number of 65,536 components. The total memory consumption by static attributes,
instance attributes, and constants is restricted to 500KB in each case. With regards to deep data objects
(tables, strings, and data references), only the fixed size of the reference is important and not the variable size
of the referenced data object.

3.7.4.2 Rule

Maintain reasonable class sizes

Ensure that classes and interfaces do not contain an excessively high number of attributes, methods and
events. The components contained must be class-specific and should not handle tasks that are extremely
different from each other. The same applies to function groups.

3.7.4.3 Details

Page: 89 of 227
Complexity is not only important on the level of procedure implementations. The number of procedures to be
considered and the data processed by these procedures are also very important when it comes to
understanding the source code.
A class, interface or function group should not be mistaken as a container that can be used for any functionality.
Function groups play the same role here as abstract final classes, which you cannot generate instances of. The
function modules correspond to static public methods, and the global data corresponds to private static
attributes. The situation should be viewed more as an abstraction of a certain subject or an object from real life.
This modularization of a complex problem in objects of a manageable size makes it easier to understand the
code. Therefore, the classes and interfaces must be designed appropriately and each class/interface must
cover a manageable function that is easy to understand.

This is obviously not the case, if a class or an interface contains a large number of attributes and methods. The
same applies to the number of function modules of a function group (with regard to the use of function groups).
Voluminous classes, interfaces, and function groups either provide functionality that is too heterogeneous or,
conversely, are highly specialized, which restricts their reusability.

Besides the high degree of complexity, which makes it more difficult to maintain voluminous classes and
function groups, you must consider another technical aspect: Even if you use a small part of the provided
functionality, the entire class/function group is loaded into the program memory, which negatively impacts the
memory usage.

3.7.4.3.1 Note

It is preferable to use multiple procedures, which are not too large and have clearly defined tasks, instead of a
small number of large procedures. On the other hand, classes should not contain too many methods. However,
these two rules are not contradictory, provided that the procedures do not become too small and are
appropriately grouped into different classes with a clearly defined task field. In this process, very specialized
classes can be created that do not require global visibility.

Functionality that is only required in a global class, function group or any other program, should therefore be
encapsulated in local classes. (All functions of function groups, subroutine pools, and executable programs
should be implemented in local classes anyway). An example of this self-contained functionality is the display
logic for classical dynpros within a function group. A meaningful reuse of classes that call the dynpros of the
function group is not possible outside the function group. Therefore, local classes are the preferred elements for
this task.

This procedure is also useful for global classes. By moving highly specialized functionality to smaller, local
classes, you reduce the number of methods of the global class, which results in a clearer overview and makes
the class easier to maintain. When you use local classes within global classes, make sure you position them
appropriately to avoid unnecessary dependencies.

Dead Code

3.7.5.1 Background

Dead code is program parts that are never executed because they are no longer required or were never
actually required at any time. This code can accumulate during the development (rejected prototypes) or
maintenance (changeover to new code without deleting the old code) of programs.

3.7.5.2 Rule

Remove dead code

Page: 90 of 227
Completely remove any unused or inaccessible program parts from live programs.
3.7.5.3 Details

Although dead code does not affect the executed program parts directly, it still has a negative impact on the
product. Program parts that cannot be accessed during program execution do not provide any benefit. Instead
they cause increased costs in the course of a program#s lifecycle because they must be identified as unused
for maintenance and further development purposes. The worst case scenario is that if these program parts are
not immediately recognized as unused, they will be reused or modified during further developments or
refactoring measures. A lot of time and effort is wasted making changes to unused code. In addition, these
program parts increase the space required in the program buffer during program execution.

Dead code also interferes with the aim of maximum test coverage by module tests using ABAP Unit or
scenario tests using eCATT. Code not used in the live system is either tested, which is very time-consuming,
or is not tested, which results in poor test coverage. Unused and inaccessible program parts must therefore
be identified and removed as quickly as possible. 3.7.5.3.1 Note

Check tools indicate dead code if it can be identified. Examples:

• The syntax check warns you about unused private methods of local classes.

• The extended program check warns you about unused declarations or statement blocks in control
structures that can never be accessed.

However, these static checks can never be complete because not every use of a program part has to be
statically recognizable. Therefore, the Coverage Analyzer is another important tool for isolating potential dead
code.

Page: 91 of 227
4 ARCHITECTURE
The guidelines in this section give you advice on how to use the ABAP programming language and are not
designed as general guidelines for the architecture or programming model of application programs on SAP
NetWeaver Application Server ABAP. It tackles only selected aspects of the architecture, namely those closely
associated with specific ABAP language constructs.

4.1 Object-Oriented Programming


Achieving an optimal object-oriented design is not an easy task and this is not the subject of these programming
guidelines. It is definitely worth consulting the relevant literature for this topic. The rules below are limited to
basic recommendations (for making source codes easier to understand and maintain) and ABAP specifics on
working with global and local classes.

Developers who have experience with object-oriented development in other programming languages should be
aware of the differences between ABAP Objects and Java:

• In Java, all superior data objects (especially container variables such as strings) are modeled using
classes. By contrast, ABAP provides very powerful, predefined types. Besides the predefined ABAP
strings, internal tables are also provided that are used for structured data storage. These tables
represent the most powerful ABAP type. Therefore, it is generally not beneficial to implement own
container types using ABAP classes.

• Java reaches a high processing speed for methods, by using optimizations and JIT compilation. In
ABAP, however, the high processing speed is primarily attained using very powerful and complex
individual statements. This is another reason why implementing own container classes is usually not
beneficial. Direct access to a suitable internal table, for example, is always faster than handwritten
access logic in ABAP.

Of course, you can transfer algorithms and a general class structure to ABAP, from an application written in
another object-oriented programming language. However, the greater the depth, the greater the differences.
Therefore, you need to make appropriate modifications, in order to transfer a detailed design in a different
language to ABAP Objects.

Encapsulation

4.1.1.1 Background

A program that is created based on the procedural programming model and that includes many procedures and
global variables is usually difficult to understand because the numerous possible interdependencies of these
publicly accessible variables and procedures are difficult to comprehend . The object-oriented approach solves
this particular problem by providing visibility sections that are not public. This enables readers who want to get
an overview of how the software functions to restrict the overview to the public interfaces of the classes
involved. The non-public visibility sections only contain details of the implementation that are not important for a
view from the outside.

Of course, this clear overview benefit is only realized in places where the developer makes use of the non-
public visibility sections. The same applies to the non-public object generation and final classes, where it is
becomes immediately clear whether objects can also be generated outside of the class or whether derived
classes can exist.

For the development or the design of an application, it is useful to encapsulate as restrictively as possible
initially, and to undo the encapsulation only where required.

Page: 92 of 227
4.1.1.2 Rule

Exploit the benefits of encapsulation

Utilize the encapsulation options provided in the form of non-public visibility sections, non-public object
generation, and final classes as much as possible. The use of units that are encapsulated in such a way should
preferably be free of side effects.

4.1.1.3 Details

This simple rule provides practical access to object-oriented programming that results in programs that are
more robust and more easily maintainable than if you use procedural ABAP, and without a prolonged object-
oriented design phase. To use encapsulation appropriately, do the following:

• Keep the number of public components of a class as small as possible (components that may be
private or protected should therefore be created in the corresponding visibility section as well).

• Declare public attributes only as READ-ONLY.

• Consider the private instantiation of classes.

• Mark classes that are not intended as superclasses as FINAL.

Conversely, within an encapsulated unit, that is, within a class, you should avoid accessing more global data
directly. Within methods, you should generally modify attributes of the class only. Write access to global data
outside the class is not recommended. Accessing data in this way should only be done using specially marked
methods, if at all. The use of methods of a class should not evoke any side effects outside the class itself.

Modularization

4.1.2.1 Background

The main programming model that was propagated before the implementation of ABAP Objects was structured
programming:

• In this model, the programs are split into procedures as appropriate.

• Sequences, branches, and loops are the only control structures permitted.

The implementation of object-oriented programming languages such as ABAP Objects does not make
structured programming obsolete. Object-oriented programming is based on the structured programming and
enhances and supplements it.

With regard to ABAP, you must note that ABAP is still a programming language of the fourth generation (4GL)
that has been developed especially for application programming in the SAP environment, that is, for mass data
processing in business applications. Therefore, ABAP includes significantly more language elements than an
elementary programming language in which the more complex functionality is usually stored in libraries. This
ranges from simple statements for string processing, which are provided as methods of string classes in other
object-oriented languages such as Java, to the processing of complex mass data objects, such as internal
tables, to very complex statements for operating interfaces such as Open SQL or for calling data
transformations (XML), for which other languages have entire class hierarchies.

Page: 93 of 227
As already mentioned, the performance of the ABAP language is therefore optimized mainly for the execution of
its complex statements for mass data processing and less for the individual method call.

4.1.2.2 Rule

Modularize Rather than Atomize

Modularize your program in classes, but not to the extent that there is an individual method for every trivial
function. Methods that consist of only one or just a few statements should be an exception in ABAP and not the
rule.

4.1.2.3 Details

You should only use methods of ABAP Objects for the implementation of functions; there are very good reasons
for this. But ABAP remains ABAP, and the good reasons for using a well-structured program are not invalidated
by the implementation of ABAP Objects. Indeed, the ABAP language elements proven and tested in so many
application cases are still valid today, are undergoing continuously development, and should be used in their
present form in ABAP Objects as well.

An already well-structured classical ABAP program, for instance a function group that fulfills a specific task and
is modularized using subroutines, should therefore be transferable to a class without any major changes to the
implementation, whereby it is provided with all the additional benefits of ABAP Objects.

However, the modularization at the level of a few single statements is and will remain untypical for ABAP. On the
one hand this is because of performance reasons, because the costs for the method call must remain low in
comparison to the costs for executing the implementation. For example, instead of providing the get_attribute
methods typical for other object-oriented languages that only set their return value to the value of an attribute
attribute, you should use public READ-ONLY attributes in ABAP. (If the read access to an attribute is linked with
further actions, for example, authorization checks, get_attribute methods are appropriate, of course.) On the
other hand, virtually all non-fundamental statements of ABAP (all language elements that do not have any
equivalent in an elementary language like Java) already play the same role that the methods of system classes
assume in other programming languages. The use of such a statement corresponds to a method call, and
another encapsulation is usually not necessary.

Also, for legibility and maintainability reasons, a method with a reasonable size is preferable to splitting into
atomic units, that is, into methods with only one or two statements.

4.1.2.3.1 Exception

Procedures that encapsulate nothing but the call of another procedure are an exception. A single procedure call
represents the implementation of an entire procedure. This applies in particular to function modules and
subroutines, which can only be created in exceptional cases anyway. They should include exactly one method
call, which delegates the implementation to ABAP Objects. In this case, the improved security through the
stricter checks in ABAP Objects outweighs the disadvantages of very short procedures.

4.1.2.3.2 Bad example

The following source code shows the rudimentary implementation of a string class in ABAP Objects. The
methods of this class each contain only a single statement. A user must generate objects of the class and call
the methods to handle the strings.

CLASS cl_string DEFINITION PUBLIC.


PUBLIC SECTION.
METHODS: constructor IMPORTING value TYPE
string OPTIONAL,

Page: 94 of 227
set_string IMPORTING value TYPE string,
get_string RETURNING VALUE(value) TYPE string,
shift_left IMPORTING places TYPE i, shift_right
IMPORTING places TYPE i,
...
PRIVATE SECTION.
DATA string TYPE string.
ENDCLASS.
CLASS cl_string IMPLEMENTATION.
METHOD constructor.
string = value.
ENDMETHOD.
METHOD set_string.
string = value.
ENDMETHOD.
METHOD get_string.
value = string.
ENDMETHOD.
METHOD shift_left.
SHIFT string LEFT BY places PLACES.
ENDMETHOD.
METHOD shift_right.
SHIFT string RIGHT BY places PLACES.
ENDMETHOD.
...
ENDCLASS.
...
CLASS application IMPLEMENTATION.
...
METHOD do_something.
DATA string TYPE REF TO cl_string.
CREATE OBJECT string EXPORTING value = 'abcde'.
... string-
>shift_left( ... ).
...
ENDMETHOD.
...
ENDCLASS.

4.1.2.3.3 Good example

The following source code shows the handling of strings typical to ABAP. A method directly declares a data
object of type string and directly uses the corresponding ABAP statements for processing.

CLASS application IMPLEMENTATION.


...
METHOD do_something.
DATA string TYPE string.
...
SHIFT string LEFT BY ... PLACES.
...
ENDMETHOD.
...
ENDCLASS.

There is a corresponding built-in function for almost every string processing statement. They can also be used
in operand positions, negating another reason for the encapsulation of statements in methods. The SHIFT
LEFT statement in this example can be replaced as follows, whereas shift_left is a built-in function:

Page: 95 of 227
string = shift_left( val = string places = ... ).

Static Classes and Singletons

4.1.3.1 Background

The classes of ABAP Objects support two types of components:

• Instance components (instance attributes, instance events and instance methods). You can only
address the instance components of a class using instances of the class (objects).

• Static components (static attributes, static events and static methods). The static components of a
class can be addressed using an object and also using the name of the class. This means they can be
used independently of a class instance.

A class that only contains static components and no instance components is referred to as a static class. A
global static class is loaded once with its class pool into the current internal session. Like every ABAP program,
it cannot be explicitly deleted from the session. The static methods (declared using CLASS-METHODS) of a
class cannot be redefined in subclasses.

A singleton is a design pattern where the class assumes the responsibility of object generation. The class
ensures that only one object exists for every internal session that is made available to users.

4.1.3.2 Rule

Do not use static classes

Use objects instead of static classes. If you do not want multiple instantiation, you can use singletons.

4.1.3.3 Details

If no real object-oriented design exists that would use the multiple instantiation of classes, for example, this
often results in the generation of classes that only contain static methods (declared using CLASS-METHODS),
when ABAP Objects are used. These methods are then used as simple procedures. However, even if multiple
instantiation is not explicitly required, object generation is preferable to the use of static classes, for the reasons
listed below. You can use the singleton design pattern to prevent multiple instantiation:

• Explicit object generation is essential for object-oriented programming. Static classes, however, are
implicitly loaded the first time they are used, and the corresponding static constructor — if available —
is executed. They are persisted in the memory for as long as the current internal session exists.
Therefore, if you use static classes, you cannot actually control the time of initialization. You have no
way of releasing the memory occupied by the attributes, as soon as the class function is no longer
required.

• Another important argument against the use of static classes is the limited functionality of the static
constructor, in comparison to an instance constructor. A static constructor has no parameter interface
and cannot propagate any exceptions. This is why you cannot always respond appropriately to an error
situation in the static constructor, which can cause a runtime error in extreme cases. However, the
exceptions of an instance constructor can be handled.

• By using static classes, you restrict your polymorphism options, which are actually provided by
objectoriented programming. On the one hand, you cannot redefine static methods. On the other hand,

Page: 96 of 227
access is not possible using reference variables (the other “pillar” of polymorphism). However, it is
worth keeping the option of polymorphism open:

o Even if you initially do not plan to overwrite the behavior of a method later on using inheritance or
redefinition, this is a request that frequently arises in the course of the further development.
o When implementing unit tests with ABAP Unit, redefining the behavior of certain methods, to
resolve problematic dependencies, is often unavoidable.

To keep the option of redefinition open, you should always use instance methods instead of static methods.

You can express the retrieval of a singleton object and the subsequent call of an instance method, by using the
very compact form of a chained method call:

cl_singleton=>get_instance( )->do_something( ).

Since an additional object reference variable and an additional factory call are omitted, there are no aesthetic
disadvantages related to the use of a singleton design pattern.

4.1.3.3.1 Exception

Classes that only cover trivial functionality can still be implemented as static classes. Here you must accurately
assess whether one of the previously mentioned aspects has any effect. The need for a class constructor can
be an indicator here. Once a static class requires a nontrivial class constructor to provide the required
functionality, you should use objects instead.

4.1.3.3.2 Bad example

The following source code shows a static class with purely static methods and how one of these methods is
used. In general, it is not immediately obvious from the source code whether the method call also calls the
static constructor or whether this has already happened earlier (following a simple attribute access, for
example).

CLASS static_class DEFINITION.


PUBLIC SECTION.
CLASS-METHODS: class_constructor,
meth1,
meth2, ..
.
ENDCLASS.
...
static_class=>meth1( ).
...

4.1.3.3.3 Good example

The following source code shows an implementation of the singleton design pattern. A static method allows
access to the only object of the class.

CLASS singleton_class DEFINITION CREATE PRIVATE.


PUBLIC SECTION.
CLASS-METHODS get_instance
RETURNING VALUE(r_instance) TYPE REF TO singleton_class
RAISING cx_some_failure.
METHODS constructor
RAISING cx_some_failure.

Page: 97 of 227
METHODS: meth1,
meth2.
...
PRIVATE SECTION.
CLASS-DATA instance TYPE REF TO singleton_class. ENDCLASS.
CLASS singleton_class IMPLEMENTATION.
METHOD get_instance.
IF instance IS NOT BOUND.
CREATE OBJECT instance.
ENDIF.
r_instance = instance.
ENDMETHOD.
...
ENDCLASS.
...
TRY.
singleton_class=>get_instance( )->meth1( ).
CATCH cx_some_failure.
...
ENDTRY.

In the above example, the get_instance method is used to return the object reference to the object created with
the first call. Therefore, this example would appear to violate the rule modularize rather than atomize. This rule
states that no method should be created in ABAP that only returns the value of an attribute. However, this
objection is not justified here, because the main task of the get_instance method is to enable the object user to
control the time of object creation. This is necessary to enable the user to respond (in the usual way) to any
exceptional situation during the object creation process.

In special cases, where object creation is performed without parameters and is always successful, you can omit
the get_instance method and publish the object reference using a READ-ONLY attribute. In this case, the object
is created within the static constructor. Therefore, this approach is still afflicted with some of the problems of
static classes described in other sections.

Inheritance

4.1.4.1 Background

Inheritance is the method by which subclasses are derived from a superclass while inheriting the components of
the superclass. A subclass can be made more specific by declaring new components and redefining instance
methods. ABAP Objects supports simple inheritance, in which a class can have multiple subclasses but only
one direct superclass. (Despite this, the interface concept does enable something like multiple inheritance to
take place, at least with regard to attributes and method declarations. Method implementations, on the other
hand, are not inherited when an interface is included.) This creates an inheritance hierarchy in an inheritance
tree, with a unique path running from each subclass to a root class. In ABAP Objects, all classes are
subclasses of the predefined abstract root class object. Final classes (classes defined using the addition
FINAL) close the bottom of a path in the inheritance tree.

4.1.4.2 Rule

Avoid using deep inheritance hierarchies

Avoid using deep inheritance hierarchies, since they are often difficult to maintain.

Page: 98 of 227
4.1.4.3 Details

Deep inheritance hierarchies are examples of successful reuse, but are also the source of maintenance
problems, due to the complexity inherent in the large number of classes involved.

• The behavior of classes deep down in the inheritance hierarchy is difficult to predict, since they
potentially inherit from a large number of methods.
• Classes with a lot of subclasses exert great influence on the system as a whole, making the
consequences of modifications to a superclass hard to predict.

• A large number of subclasses may also indicate an unsuitable level of abstraction.

To prevent unintended reuse of your classes by inheritance, we recommend that you use final classes to close
the paths of inheritance trees.

4.1.4.3.1 Note

If your main aim is to exploit the possibilities of polymorphy, then interfaces are often a preferable solution to
inheritance. If all you want to do is use interfaces, then method interfaces should be used instead of abstract
classes. These can be used to create composite interfaces. In ABAP, on the other hand, a composite interface
is impossible due to the nature of simple inheritance using classes.

Class References and Interface References

4.1.5.1 Background

Interface components in objects can be addressed using a class reference variable or an interface reference
variable. If you use a class reference variable, the interface component is addressed using the name of the
interface and the interface component selector (~). If you use a suitable interface reference variable, the
component is addressed directly using its name.

4.1.5.2 Rule

Address interface components using interface reference variables

From outside a class, only access its interface components using a relevant interface reference variable; do not
use the interface component selector (~).

4.1.5.3 Details

Accessing interface components externally using an interface reference variable makes code easier to
understand because it is clear that the user of the class is interested in exactly the aspect provided by the
interface. Accessing interface components using a class reference variable, on the other hand, suggests that
components are used that are not provided by an interface. As a rule, only use the interface component selector
within classes and interfaces, to address the interfaces included there. If you want to provide an interface
component of an included interface as a separate component, you can declare an alias name by using
ALIASES.

4.1.5.3.1 Bad Example

Page: 99 of 227
The following source code shows an interface method call using a class reference variable and the interface
component selector (~); this is not recommended, as mentioned in the rule above.

CLASS cl_class DEFINITION PUBLIC.


PUBLIC SECTION.
INTERFACES if_intf.
...
ENDCLASS.
...
DATA cref TYPE REF TO cl_class.
... cref-
>if_intf~meth( ).
...

4.1.5.3.2 Good Example

The following source code shows the method call from the above example, but using an interface reference
variable. Instead of cref->if_intf~meth, iref->meth is used to express that components of a class are accessed
that are on the same hierarchy level as all public components, but in another part of the public interface.

CLASS cl_class DEFINITION PUBLIC.


PUBLIC SECTION.
INTERFACES if_intf.
...
ENDCLASS.
...
DATA iref TYPE REF TO if_intf.
... iref-
>meth( ).
...

Local Types for Global Classes

4.1.6.1 Background

Within class pools, as in virtually any other ABAP program, data types, local interfaces, and local classes can
be defined to ensure a better structure of the implementation of the global class. From a technical point of view,
these optional declaration parts, together with the declaration part of the global class, form the global
declaration part of the class pool.

These local declarations of a class pool are invisible outside the class pool and can therefore only be used in
the private visibility section (PRIVATE SECTION) of the declarations of the global class or within their method
implementations. These two usage types have different technical visibility requirements because friends of a
global class have access to its private visibility section. Local type declarations that are used in the PRIVATE
SECTION must therefore be accessible for any possible friends of the class, whereas those type declarations
that are only used within the method implementations are completely meaningless for other classes.

In general, local classes consist of the declaration part and the associated method implementations. These are
invisible to the friends of the global class and have thus technically the same visibility requirements as local
type declarations that are only used within the implementation.

Local data types, interfaces, and classes are created within a class pool using the "Class-Local Types" function
in Class Builder, which stores these declaration and implementation parts in the include programs provided for
this purpose. There is a distinction between the two areas, Local Class Definitions/Types and Local Class
Implementations, to meet the different technical visibility requirements mentioned above.

Page: 100 of 227


4.1.6.2 Rule

Position local declarations appropriately

Position the local declarations of a class pool at appropriate positions depending on the requirements. Types
that are only used within the implementation of the global class need to be in a different position than types that
are also addressed in the PRIVATE SECTION of the global class.
4.1.6.3 Details

From the perspective of a class pool, all local type definitions and the associated implementations of the local
classes can be saved in the "Local Class Definitions/Types" area. However, such an approach is
disadvantageous from the dependency management perspective. Dependent classes (subclasses and friends
of the global class) only have to be invalidated for changes to the local type declarations of a class pool that are
used in the PRIVATE SECTION of the global class. But technically speaking, this invalidation occurs for all
changes in the Local Class Definitions/Types area. For this reason, the additional area "Local Class
Implementations" which is intended for local type declarations that are only used within the class
implementation of the global class, and for the implementation part of local classes. If this area is changed,
dependent classes are not invalidated.

To prevent unnecessary new generations of other classes that are based on unwanted technical dependencies,
the class-local types must be defined in Class Builder at the appropriate positions after changes have been
made to the global class:

• Choose Goto > Class-Local Types > Local Class Implementations to declare types like this that are
only used within the method implementations of the global class. The local classes should be
implemented here as well.

• Choose Goto > Class-Local Types > Local Class Definitions/Types to display the types that can also
be referenced in the PRIVATE SECTION. Declaration and implementation of a local class are only
supposed to be distributed across the areas Local Class Definitions/Types and Local Class
Implementations if they are to be referred to in the PRIVATE SECTION. However, if the local class is
only used within the implementation of the global class, both the declaration and the implementation
are to be carried out in the Local Class Implementations area.

4.1.6.3.1 Note

The rule specified here specializes the general rule implement global declarations centrally with regard to class
pools. They are especially oriented toward the external call of methods of their respective global class and are
therefore particularly integrated within a dependency network. For this reason, the rule just mentioned cannot
apply to its full extent.

Instance Constructor

4.1.7.1 Background

When you define an ABAP class, you specify who creates an instance of this class or who may access the
instance constructor of the class. To do this, you use the CREATE addition of the CLASS ... DEFINITION
statement. The CREATE PUBLIC addition is the default setting and allows for the instancing by any user of the
class. By specifying CREATE PROTECTED, you can restrict the object creation to the class itself and its
subclasses. With the CREATE PRIVATE addition, objects can only be created by the class itself. The restriction
of the object creation to the class itself is useful in connection with the singleton design pattern, for example,
where the class itself performs the object creation.

Page: 101 of 227


From a technical point of view, the instance constructor can be declared in all visibility sections that are more
general or equal to the instantiation specified in the CREATE addition of the CLASS ... DEFINITION statement,
using the METHODS constructor statement. However, the actual visibility is controlled by the CREATE addition.

4.1.7.2 Rule

Declare the instance constructor in the public visibility section.


Always declare the instance constructor of a global class in its public visibility section and independently of the
instantiation specified by the CREATE addition in the class definition.

4.1.7.3 Details

The components of global classes are stored internally, separated according to the visibility section they belong
to. Depending on the usage type of the class, only parts of the class are considered by the ABAP Compiler
during compilation. This procedure requires that the constructor of a global class is always declared in the
public visibility section of the class. For these technical reasons, the instance constructor of a global class is
always supposed to be declared in the public visibility section (PUBLIC SECTION). If it is declared in another
visibility section, in individual cases this may result in unjustified syntax errors when global classes are used.
Exception The technical restrictions mentioned only apply to the processing of global classes. Within local
classes, the instance constructor can also be defined in other visibility sections. However, this positioning
should correspond with the visibility section specified using the CREATE addition. Such a strategy enables you
to use types for the interface of the instance constructor of a local class that are only accessible in a restricted
visibility section.

4.1.7.3.1 Exception

The technical restrictions mentioned only apply to the processing of global classes. Within local classes, the
instance constructor can also be defined in other visibility sections. However, this positioning should correspond
with the visibility section specified using the CREATE addition. Such a strategy enables you to use types for the
interface of the instance constructor of a local class that are only accessible in a restricted visibility section.

4.2 Error Handling


Error situations are always a possibility when a program is being executed. These can be caused by:

• internal errors produced by faulty implementations or incorrect use of services

• external errors produced by incorrect user input or unexpected resource bottlenecks

ABAP offers various method for responding to error situations like these.

Reaction to Error Situations

4.2.1.1 Background

ABAP provides the following concepts that a program can use to properly react to different error situations:

• Exceptions

Exceptions are events in the execution of an ABAP program that interrupt the program when it is not
possible for the program to continue in a meaningful way. Exceptions are raised either by the ABAP

Page: 102 of 227


runtime environment or with ABAP statements (RAISE EXCEPTION) in the program. Exception
handling enables you to react to these events. An exception that is not handled results in a runtime
error; that is, the program terminates and outputs a short dump that describes the exception.

• Assertions

Assertions formulate conditions in a program that must be met to ensure a proper continuation of the
program. An assertion is defined by an ASSERT statement.
• Messages

Messages are texts that can contain up to four placeholders for value replacements and that can be
displayed or otherwise sent using the MESSAGE statement.

These three concepts either involve the handling of the error situations by the program or the user (exceptions
or error messages), or result in a controlled program termination (assertions or exit messages).

4.2.1.2 Rule

Select an appropriate reaction to error situations

Select the appropriate concept of error handling (exception, assertion, or message) for the respective error
situation so that the error can either be handled adequately in the further course of the program or is terminated
in a controlled manner.

4.2.1.3 Details

For each error situation, you should decide on one of the three concepts for error handling:

• Exceptions are to be used in all unexpected situations that the user does not have under control.
These include, for example, invalid parameter values during the procedure call or unavailable external
resources, such as files.

• Assertions are to be used to detect inconsistent program states that necessitate an immediate
program termination.

• Messages are to be used only as dialog messages for error dialogs within the scope of classical
dynpro processing (if still available). If you want to implement a program termination in situations where
it is not a good idea for the program to continue, use assertions from now on instead of termination or
exit messages.

The MESSAGE statement is not only used to display dialog messages in a classic dynpro, but can also be
deployed to terminate a program in a controlled manner or raise classic exceptions in the MESSAGE ...
RAISING variant if the appropriate message type is selected. This invites you to combine the different concepts,
which may lead to problems. This can be traced back to the old programming model that was driven exclusively
by classical dynpros, in which an error situation directly required the output of a message to the user.

For contemporary programming that takes the separation of concerns (SoC) into account, the question of
whether a message is to be sent to the user in the event of an error can usually only be answered in a higher
software layer. The layer in which such an error situation occurs must therefore react with an exception initially,
which in turn represents a new situation for a higher layer, to which it can react with a dialog message or any
other error message.

Page: 103 of 227


Classical and Class-Based Exceptions

4.2.2.1 Background

For reasons of downward compatibility, there are two options to define treatable exceptions yourself in ABAP:

• Classical Exceptions
These exceptions can only be declared in the interfaces of methods or function modules using

EXCEPTIONS and can be raised within such a procedure using the RAISE or MESSAGE RAISING
statements. The procedure caller can use the addition EXCEPTIONS of the statements meth( ... ) or
CALL FUNCTION to assign return codes for the system field sy-subrc to the exceptions the caller
wants to handle and evaluate them after the call.

• Class-Based Exceptions
These exceptions are defined by exception classes, from which the system may generate an exception
object when an exception is raised (if a handler uses the INTO addition for CATCH). A class-based
exception can either cancel the current context or allow for a resume. Exceptions are raised using the
RAISE EXCEPTION statement, and handling occurs using CATCH in a TRY control structure.
Classbased exceptions can be raised in any procedures and can be further propagated by any
procedures.

The coexistence of the two exception concepts is regulated as follows:

• Classical and class-based exceptions cannot be declared together in the interface of a procedure.
Within a processing block, either only classical or only class-based exceptions can be raised.

• For reasons of interoperability, within a processing block class-based exceptions can be handled and
evaluate the return values of function modules and methods using classical exceptions.

4.2.2.2 Rule

Using Class-Based Exceptions

Only raise class-based exceptions in new procedures if you can dispense with classical exceptions from the
technical point of view.

4.2.2.3 Details

Self-defined classical exceptions are little more than return values. If a classical exception is raised in a
procedure using the RAISE statement, the sy-subrc system field is set according to the raised exception after
the return to the calling program. The calling program itself must always check, by querying sy-subrc, whether
an exception occurred and react to it if required, for example, by appropriate handling or explicit forwarding to
its own calling program (by raising a separate equivalent exception). This does not improve the clarity of the
program.

The occurrence of class-based exceptions, however, results in a change of the program flow. They can either
be handled directly or propagated upwards along the call hierarchy. In this way, not every procedure (method)
has to consider every possible exception situation itself. This supports the separation of concerns within an
application. Because the exception can be represented by an object of an exception class, this exception object
can gather additional information on the exception situation and transport it to the handler. In contrast to
classical exceptions, this can also include specific exception texts.

Page: 104 of 227


By default, raising an exception stops the entire current context even if the exception is handled. However, there
may be situations (mass data processing, for instance) in which a single error does not justify cancelling an
entire service. For these cases, you can raise and propagate class-based exceptions as resumable
(RESUMABLE). A handler can decide whether a service is canceled completely or is resumed using the
RESUME statement, for example after a corresponding log entry has been written.

Class-based exceptions completely replace the classical exceptions for new code (of course, there are
exceptions to this rule) and add resumability. Although classical exceptions on the raiser side are completely
obsolete from a technical point of view, you must still consider the following for older code: Even if you have the
raiser side under control, you cannot simply change older procedures over to class-based exceptions, because
then you would have to adapt all usage locations.
When you call existing procedures that use classical exceptions, you must continue to handle them in the new
code. In this case, we recommend mapping the classical exceptions to equivalent class-based exceptions by
using RAISE EXCEPTION. In this way, you achieve a class-based error handling that is uniform to the outside.
The exception situation can then be forwarded to higher call layers without each layer having to react to this
situation explicitly.

4.2.2.3.1 Exception

Since class-based exceptions are currently not supported in remote-enabled function modules (RFM), classic
exceptions still need to be implemented and handled for remote function calls (RFCs).

4.2.2.3.2 Bad example

The following source code shows the declaration and the raising of a classical exception in a method as well as
their handling by evaluating sy-subrc after a call of the method. This procedure infringes the above rule. .

CLASS application DEFINITION.


PUBLIC SECTION.
METHODS do_something
EXCEPTIONS application_error.
ENDCLASS.
CLASS application IMPLEMENTATION.
METHOD do_something.
...
RAISE application_error.
...
ENDMETHOD.
ENDCLASS.
...
... oref TYPE REF TO application.
...

oref->do_something(
EXCEPTIONS application_error = 4 ).
IF sy-subrc <> 0.
...
ENDIF.

4.2.2.3.3 Good example

The following source code shows the definition of an exception class, its declaration, and the raising in a
method as well as its handling using CATCH after the call of the method in a TRY block.

CLASS cx_application_error DEFINITION


INHERITING FROM cx_static_check. ENDCLASS.

Page: 105 of 227


CLASS application DEFINITION.
PUBLIC SECTION.
METHODS do_something
RAISING cx_application_error.
ENDCLASS.
CLASS application IMPLEMENTATION.
METHOD do_something.
...
RAISE EXCEPTION TYPE cx_application_error.
...
ENDMETHOD.
ENDCLASS.
...
... oref TYPE REF TO application.
...

TRY.
oref->do_something( ).
CATCH cx_application_error.
...
ENDTRY.

This simple example is perhaps not the most obvious demonstration of the great advantage of class-based
exceptions over classical exceptions. However, the advantage is clearly seen in nested procedure calls and the
handling of exceptions that were raised in more distant call levels.

Exception Categories

4.2.3.1 Background

Each class-based exception belongs to one of three different exception categories, each of which define
whether the exceptions need to be declared in procedure interfaces. The assignment of an exception to an
exception class is realized (technically) using inheritance. All exception classes are subclasses of the following
abstract global classes, which themselves inherit from CX_ROOT:

• CX_STATIC_CHECK
Exceptions of this category must be declared explicitly in the interface of a procedure, if they are to be
propagated from this interface. The syntax check makes a static check to determine whether all
exceptions raised in the procedure with RAISE EXCEPTION or declared in the interfaces of called
procedures are either handled with CATCH or explicitly declared in the interface.

• CX_DYNAMIC_CHECK
Exceptions of this category must also be declared explicitly in the interface of a procedure to enable
them to be propagated. This is not subject to a static syntax check, however, and is checked
dynamically at runtime instead.

• CX_NO_CHECK
Exceptions of this category cannot be declared explicitly in the interface of the procedure. The class
CX_NO_CHECK (and consequently its subclasses) are always declared implicitly and the associated
exceptions are always propagated.

4.2.3.2 Rule

Page: 106 of 227


Use a suitable exception category

When creating and raising class-based exceptions, always use an exception category suitable for the current
error situation:

• CX_STATIC_CHECK for the static protection of the exception handler

• CX_DYNAMIC_CHECK for error situations that can be prevented by preconditions


• CX_NO_CHECK for situations that cannot be handled immediately

4.2.3.3 Details

The exception categories are designed for the the following error situations:

• As a rule, exceptions that are raised in a procedure should be handled there or declared in the
interface for the procedure in order to declare to the caller which exceptions are to be expected. A
syntax check to verify this is run on exceptions from the CX_STATIC_CHECK category. This category
is therefore always warranted if a procedure (method) is to be forced to handle an exception or to at
least forward it
explicitly. However, if an exception can be prevented by prior checks, exceptions of the
CX_DYNAMIC_CHECK category are preferable.

• If the program logic can eliminate potential error situations, the corresponding exceptions do not have
to be handled or declared in the interface. This is the case if prior to a division, for example, there is an
explicit precondition for the denominator not to equal zero. In this case, exceptions from the
CX_DYNAMIC_CHECK category can and should be used. These exceptions only need to be handled
and declared if their occurrence cannot be otherwise prevented. In well modeled applications,
exceptions are generally prevented by incorporating appropriate conditions in program code and
CX_DYNAMIC_CHECK category should then be the most frequently used exception category.

• For exception situations that can occur at any time and that cannot be handled directly, the
CX_NO_CHECK category can be used. Otherwise, all exceptions that can be raised due to resource
bottlenecks would have to be caught or declared. These exceptions would then have to be specified in
practically every interface, which would result in more complex programs lacking in clarity.

4.2.3.3.1 Note

The resumability of a class-based exception is not an attribute of the exception class; it is defined instead by the
RESUMABLE addition of the RAISE EXCEPTION statement when the exception is raised. This attribute can be
lost for exceptions of the categories CX_STATIC_CHECK and CX_DYNAMIC_CHECK during propagation, if
the exceptions are not also declared there using RESUMABLE. CX_NO_CHECK always preserves its
resumability implicitly.

Exception Texts

4.2.4.1 Background

Each global exception class has a predefined exception text that has the same name as the exception class.
The predefined text can be edited in Class Builder on the Texts tab page and additional exception texts can be
defined. The exception texts of an exception class can be created either by referencing messages or as texts in
the OTR (Online Text Repository).

Page: 107 of 227


For each exception text, Class Builder creates a static constant in the exception class with the same name as
the exception text. When the exception is raised, this can be passed to the parameter TEXTID of the instance
constructor to determine the exception text. If the parameter is not passed, the predefined exception text with
the same name as the exception class is used.

From a technical perspective, the parameter TEXTID of the instance constructor can also be used to pass
messages or texts from OTR as exception texts.
4.2.4.2 Rule

Create suitable exception texts in the exception class and only use these texts

When you create an exception class, make an informed decision about the text category (messages for user
dialogs or an OTR text for internal texts) in which you create the exception texts. Only the associated texts can
be used when an exception is raised.

4.2.4.3 Details

The following guideline tells you how to choose the text category:

• Message texts should only be used if the text is to be sent to the program user. This might be the case
with application programs but should generally be avoided in system programs. One other
disadvantage of using message short texts is that they are limited to 73 characters.

• Texts from OTR should mainly be used in system programs where text is not to be sent to the program
user.

From a technical perspective, it is possible to pass a data object to the input parameter TEXTID of the instance
constructor when an exception is raised. This data object specifies either a message or an OTR text, depending
on the text category. We strongly recommend that you avoid this approach, however. If the parameter TEXTID
is used, an exception can only be raised with the texts specific to it. Only the associated constants of the
exception class can be passed to the input parameter TEXTID of the instance constructor.

4.2.4.3.1 Exception

In cases where a class-based exception is used to wrap a classic exception and MESSAGE ... RAISING is
used to associate this classic exception with a message text, the class-based exception can use the same
message text regardless of whether the program in question is a system program or application program.

4.2.4.3.2 Note

Classic exceptions are not associated with exception texts. If classic exceptions are required for reasons of
downward compatibility, the statement MESSAGE ... RAISING gives the option of emulating exception texts
here. Using MESSAGE ... RAISING in cases in which non-class-based exceptions must still be used is
preferable to using the statement RAISE, because it offers the option of providing additional text information
with an exception.

4.2.4.3.3 Bad example

The following source code passes a UUID for an OTR text to the input parameter TEXTID of the instance
constructor when an exception is raised. According to the rule above, however, only exception texts from the
exception class can be passed, with each exception class containing the corresponding constants.

...
DATA otr_id TYPE sotr_conc.
otr_id = '9753EBD0102AD0418D902B8D972083C4'.

Page: 108 of 227


RAISE EXCEPTION TYPE zcx_exception_text
EXPORTING
textid = otr_id.
...

4.2.4.3.4 Good example


The following source code passes the constant for the associated OTR text to the input parameter TEXTID of
the instance constructor when an exception is raised, as specified by the rule above.

...
RAISE EXCEPTION TYPE zcx_exception_text
EXPORTING textid =
zcx_exception_text=>zcx_exception_text.
...

Using Exception Classes

4.2.5.1 Background

The concept of freely definable exception classes involves being able to create an exception class that
adequately describes the exception situation in question. The description consists both of the name of the
exception class, the associated exception texts, and their documentation. You can divide an exception class
into multiple subexceptions by creating multiple exception texts. Subclasses of exception classes can be used
to make the information even more specific.

4.2.5.2 Rule

Only use suitable exception classes

When describing an error situation, only use exception classes with the correct category and name, the
appropriate attributes and texts, and which contain the correct documentation. Do not reuse inappropriate
exception classes.

4.2.5.3 Details

Reusing existing exception classes with the wrong content removes all benefits of freely definable exception
classes. The generated exception object cannot describe the exception situation adequately. It also makes it
very difficult to maintain and analyze the code. In particular, you run a great risk of handling the exception
incorrectly. This is because a caller layer higher up in the hierarchy never expects the exceptions it handles to
be raised by a situation with the wrong semantics.

The following procedure is recommended for raising correct exceptions, where you must take care that the right
exception category is used:

1. Search for an existing exception class that is released for use in the current concept (and as part of the
package concept) and which matches that error situation exactly.
2. Make an existing, almost ideal exception class more specific by passing on and/or adding new
exception texts.
3. Create an new ideal exception class, possibly as a part of a predefined inheritance hierarchy.

4.2.5.3.1 Bad Example

Page: 109 of 227


The following source code shows the incorrect use of the system class cx_sy_arithmetic_overflow (which exists
in every system) for an application-specific exception situation. This system exception should usually only be
raised by the ABAP runtime environment when an arithmetic calculation takes place.

CLASS warehouse DEFINITION.


PUBLIC SECTION.
METHODS calculate_storage_capacity
RAISING cx_sy_arithmetic_error.
ENDCLASS.
CLASS warehouse IMPLEMENTATION.
METHOD calculate_storage_capacity.
...
RAISE EXCEPTION TYPE cx_sy_arithmetic_overflow.
...
ENDMETHOD.
ENDCLASS.

4.2.5.3.2 Good Example

The following source code shows how an application-specific exception class is used that has been created
especially for the situation and whose name reflects the topic.

CLASS cx_warehouse_out_of_capacity
DEFINITION INHERITING FROM
cx_static_check. ENDCLASS.
CLASS warehouse DEFINITION.
PUBLIC SECTION.
METHODS calculate_storage_capacity
RAISING cx_warehouse_out_of_capacity.
ENDCLASS.
CLASS warehouse IMPLEMENTATION.
METHOD calculate_storage_capacity.
...
RAISE EXCEPTION TYPE cx_warehouse_out_of_capacity.
...
ENDMETHOD.
ENDCLASS.

Handling and Propagating Exceptions

4.2.6.1 Background

If a class-based exception occurs, it is automatically propagated by the call layers until the exception is handled
or an interface is violated:

• If the exception occurs in a TRY block, the system searches for a suitable CATCH block to handle it.

• If the user leaves the procedure context during the handler search, the procedure's interface will be
checked. Only exceptions declared in the interface can be propagated from the procedure. Exceptions of
the categories CX_STATIC_CHECK and CX_DYNAMIC_CHECK must be declared explicitly with
RAISING, while exceptions of category CX_NO_CHECK are always declared implicitly. If the interface is
violated, the predefined exception, CX_SY_NO_HANDLER, is raised at the calling position of the
procedure. A reference to the original exception is defined in PREVIOUS attribute of the exception.

Page: 110 of 227


If no handler is found in any of the TRY control structures involved, or if the exception occurs outside a TRY
control structure, this results in a runtime error at the raise position of the exception. The short dump of the
runtime error contains the name of the exception class and the exception text.

4.2.6.2 Rule

Catch exceptions or forward them when appropriate


Only catch exceptions that you can handle appropriately in the current context. When you forward exceptions
from the underlying software layers, they are supposed to be mapped to corresponding exceptions of the
current software layer.

4.2.6.3 Details

When you call a procedure whose interface includes class-based exceptions, you must decide (for each
exception) whether the exception can be handled at this position or should be forwarded to your own calling
program. Exceptions that cannot be handled appropriately at the current call level must be forwarded to the
superordinate call level. For class-based exceptions, this is done implicitly by avoiding handling within the
current call level. You should only allow a runtime error to occur in cases where you are absolutely sure that
catching or propagating exceptions is not useful.

When you forward exceptions along the call sequence across multiple layers, they usually move from lower
technical layers to higher, more abstract layers that are closer to the application. The calling program in these
higher layers does not necessarily know the implementation details of the lower layers and therefore cannot
interpret exceptions appropriately. For this reason, exceptions should not exceed the boundaries between
software layers. Instead they should be mapped to suitable exceptions with a higher degree of abstraction.

Therefore, we recommend that you do not rely on automatic propagation for forwarding between software
layers. Instead, you should catch the original exception and map an exception in the current context by raising a
new exception (the context between the originally raised exception and the final exception should be preserved
by using the PREVIOUS attribute). This ensures that the calling program of a procedure only receives
exceptions that it can understand. This type of procedure is required anyway, for package encapsulation
purposes, if exceptions have to be forwarded between software layers.

4.2.6.3.1 Note

Forwarding the exceptions to higher software layers usually results in a generalization of previously very special
exceptions. The more general an exception is, the higher the software layer usually is in which it is handled. In
particular, the most general of all possible exceptions (in other words, the exceptions of type
CX_STATIC_CHECK, CX_DYNAMIC_ CHECK, CX_NO_CHECK, or CX_ROOT) should only be caught at the
highest software layers and only if a runtime error must be avoided at all costs.

Cleanups After Exceptions

4.2.7.1 Background

Every TRY control structure can contain a CLEANUP block. If a class-based exception occurs in the TRY block
of the same TRY control structure, but is handled in a CATCH block of an external TRY control structure, the
CLEANUP block is executed before the context of the exception is deleted. Therefore, when a handler is
executed the CLEANUP blocks of all TRY control structures that have been unsuccessfully searched for a
handler up until that point are executed from the inside out.

Page: 111 of 227


The BEFORE UNWIND addition for the CATCH statement determines whether execution takes place before or
after handling. However, the CLEANUP blocks are not executed if RESUME is used during exception handling
to restart in the context of the exception.

4.2.7.2 Rule

Cleanup Before Forwarding

Before forwarding an exception to higher-level call layers, perform the necessary cleanups in the CLEANUP
block.
4.2.7.3 Details

Each exception changes the program flow and can thus pose a significant risk to the consistency of an
application. If you decide not to handle an exception, but to forward it, you must make sure that you leave the
current software layer in a consistent state. You can implement the CLEANUP block in this case, to execute
cleanups before the exception is forwarded to higher-level software layers.

4.2.7.3.1 Bad Example

The following source code shows the forwarding of an exception without first explicitly closing an open resource
(in this case a database cursor). The closing of the database cursor is implicitly delegated to any exception
handler.

TRY.
OPEN CURSOR db_cursor
FOR SELECT ...
...
CATCH cx_sy_sql_error INTO exc.
RAISE EXCEPTION TYPE cx_persistency_error
EXPORTING previous = exc.
ENDTRY.

4.2.7.3.2 Good Example

The following source code shows the same example as above, but the database cursor is closed in the
CLEANUP block.

TRY.
OPEN CURSOR db_cursor
FOR SELECT ...
...
CATCH cx_sy_sql_error INTO exc.
RAISE EXCEPTION TYPE cx_persistency_error
EXPORTING previous = exc.
CLEANUP.
CLOSE CURSOR db_cursor.
ENDTRY.

Assertions

4.2.8.1 Background

The ASSERT statement is used to express an assertion in an ABAP program. Such an assertion is either
always active or can be activated externally by assignment to a checkpoint group. When the program reaches

Page: 112 of 227


an active assertion, it evaluates the corresponding condition. If the condition is violated, the following happens,
depending on the type of activation:

• The program is terminated with the runtime error ASSERTION_FAILED.

• The program branches to the ABAP Debugger.

• A log entry is generated.

Assertions, together with breakpoints and logpoints, form the checkpoints of a program; these are not part of
the application logic, but are used for development and maintenance support.
4.2.8.2 Rule

Using Assertions

Use assertions to check the status of a program for consistency at all locations where this is possible.

4.2.8.3 Details

Each program logic is based on certain assumptions. If these assumptions are not met, there are obviously
errors in the program and there is no point in executing it any further. In this case, you should stop the
execution of the program immediately to avoid any further damage, such as persisted incorrect data. In this
way, you can also identify errors early on that would otherwise remain undiscovered.

The ASSERT statement is most suitable for guaranteeing this consistency since it is linked directly to a
condition and terminates the program if this condition is violated.

Furthermore, assertions make program maintenance easier by enabling developers to express their
assumptions explicitly. The reader of the source text is immediately aware of these assumptions; this gives
them a better understanding of the program logic.

If it will take too long to check an assertion condition, you can use the activatable assertions that are linked to
checkpoint groups. These can be activated selectively during development, testing, or troubleshooting;
otherwise they are not performed. If you suspect an error in a productive system, you can also activate
activatable assertions there.

4.2.8.3.1 Exception

Do not use assertions to check statuses that are out of the developer's control, such as invalid call parameter
values or availability of external resources. In this case, use exceptions, as this enables the caller to react to
such unexpected statuses.

4.2.8.3.2 Example

The following source text shows a program extract in which a line is read from an internal table. The program
logic here assumes that this access is always successful. This expectation is checked at runtime by the
subsequent assertion, and also documented for the reader.

...
READ TABLE items INTO current_item INDEX current_index.
ASSERT sy-subrc = 0.
...

Page: 113 of 227


Messages

4.2.9.1 Background

Messages are texts that are created using a message editor (transaction SE91). They are stored in the system
table T100. In ABAP programs, the statement MESSAGE is the main element for using messages. This
statement sends a message; by specifying a message type, the display type and subsequent program behavior
can be defined. For this reason, a distinction is made between the following message types:

• Status message (S)

• Information message (I)


• Warning (W)

• Error message (E)

• Termination (abort) message (A)

In addition, there is a special message type, exit message (X), which causes a targeted program termination
with a runtime error.

The actual system behavior after a message is sent is highly context-dependent. The current version of the
ABAP keyword documentation contains a detailed list of effects caused by different message types in different
contexts (such as dialog processing, background processing, during an RFC and during the processing of
HTTP requests).

The original purpose of messages is to act as dialog messages to display short information (types I and S) and
handle incorrect user input (types W and E), during classic dynpro processing. Messages also have aspects
that overlap with exceptions:

• The statement MESSAGE ... RAISING is a combination of the statements MESSAGE and RAISE
which enables classic exceptions to be associated with messages.

• Using the special, predefined classic exception, error_message, error and termination messages (that
occur when function modules run) can be handled in the same way as exceptions. This also applies to
messages sent from the ABAP runtime environment (for example, when the automatic input check of
classic dynpros is running).

• In exception classes, exception texts can be defined with a reference to messages. The message types
A and X can also be used for direct program terminations.

4.2.9.2 Rule

Only use messages for error handling in classic dynpros and as exception texts

Only send dialog messages in PAI processing of classic dynpros. Messages should only be used as exception
texts and should no longer be used anywhere else. In particular, messages should no longer be used to force
program terminations.

4.2.9.3 Details

The wide use of messages for different purposes can be traced back to the previous programming model, which
was only driven by classic dynpros. Here, an exception situation usually always required the direct output of a

Page: 114 of 227


message to the user. This concept was adopted for other situations, such as targeted program terminations.
Triggering a dialog message within application logic procedures violates the SoC principle and limits the
usability of the relevant procedure (Method) to the context of classic dynpro processing. The predefined
exception error_message should be regarded as a workaround that enables procedures to be executed for
sending messages in the application layer or in the background.

In new programs, the use of messages should be restricted as described below.

4.2.9.3.1 Dialog Messages

In cases where classic dynpros are still used, message types E, I, S, and W are still suitable for sending
information to the user or for running error dialogs at the time of PAI (which is the original purpose of these
messages types). Running error dialogs, in particular, is supported by the statements FIELD and CHAIN of the
dynpro flow logic.
4.2.9.3.2 Exception Texts

Messages can be used as exception texts and sent to the program user. This primarily involves exceptions in
the presentation layer.

The statement MESSAGE allows these exception texts to be sent directly as dialog messages. A reference to a
corresponding exception object can be specified directly. From a technical point of view, a reference must be
specified to an object whose class includes the interface IF_T100_MESSAGE.

In addition, messages in procedures where classic exceptions are still necessary can replace real exception
texts; use the statement MESSAGE ... RAISING instead of RAISE. During this process, information about the
exception text is passed to the handler, in the system fields sy-msgid and sy-msgv1 - sy-msgv4. These fields
are filled using the statement MESSAGE . This works especially well for handling exceptions during an RFC, for
which class-based exception handling is not possible.

4.2.9.3.3 Program Terminations

Message types A and X cause program terminations (aborts) and should no longer be used:

• If a termination message of type A is sent, the statement ROLLBACK WORK is executed implicitly.
This can lead to unexpected results, if the message is handled with error_message as a classic
exception (rather than causing a program termination) To be on the safe side, the statements
ROLLBACK WORK and LEAVE PROGRAM should be used explicitly to exit the program.

• If a message of type X is sent, the program is terminated with the runtime error MESSAGE_ TYPE_X.
Due to internal inconsistencies, assertions should now be used for forced program terminations. The
values passed using the addition FIELDS of the statement ASSERT are usually better suited to
problem analysis than a message.

4.2.9.3.4 Exception

Exit messages can still be used, if it is absolutely necessary to display message text in the short dump of the
runtime error. However, this should not be misunderstood as communication with the user. A runtime error is not
a suitable way of communicating with users. For a simple, unconditional program termination, however, exit
messages should no longer be used. Instead, wherever necessary, a logical condition that is always false
should be specified in ASSERT.

Page: 115 of 227


4.3 User Interfaces
The user interface is the interface between a (human) user and a machine, in this case between the user and
the ABAP program that is running. In the ABAP environment, graphical user interfaces (GUIs) are used which
can be operated using a keyboard, mouse, or other input devices. They are based on assorted interface
technologies and use either SAP's own SAP GUI or are Web-based technologies that generate HTML pages
displayed using Web browsers.

Selecting the User Interface Technology

4.3.1.1 Background

Various UI technologies can be used in the ABAP environment. We distinguish between classic technologies,
which are based on the SAP GUI and are almost completely integrated into the ABAP language, and new
Webbased technologies, which display the UI in a Web browser and are accessed through object-oriented
interfaces in ABAP.
The classic SAP GUI technologies are:

• Classic dynpros
A classic dynpro is a component of an ABAP program. It is created using the Screen Painter in the
ABAP Workbench and called using either a transaction code or the CALL SCREEN statement. Every
time a dynpro is called, a dynpro sequence is started.

• Selection Screens
A selection screen is a specific classic dynpro that is not created manually in the Screen Painter.
Instead, you define it using the PARAMETERS, SELECT-OPTIONS, and SELECTION-SCREEN ABAP
statements. A selection screen is called either implicitly when executable programs are started or
explicitly using the CALL SELECTION-SCREEN statement.

• Classic Lists
Classic lists are used to output data in a structured and formatted display. The formatted data is stored
in a list buffer using specific ABAP statements (such asWRITE, FORMAT) and displayed on a special
system dynpro. Classic lists are called either automatically (when an executable program is run) or with
the LEAVE TO LIST-PROCESSING statement.

The new Web-based technologies are:

• Business Server Pages


Business Server Pages (BSP) are the counterpart to JavaServer Pages (JSP). BSPs are HTML pages
with content that is partly dynamic. The dynamic content is generated by server-side scripts that are
written in ABAP. On the application server, this type of script occurs as a generated ABAP Objects
class. You create Business Server Pages using the Web Application Builder of the ABAP Workbench.

• Web Dynpro ABAP


Web Dynpro ABAP is a technology for creating platform-independent, Web-based interfaces. The
architecture of Web Dynpro is based on the Model View Controller approach (MVC) for SoC. The three
components of the model view controller are the data model, which describes the application, the
presentation view, and the program controller for responding to user actions. Web Dynpro applications
are created using the Web Dynpro Explorer in the ABAP Workbench and appear on the application
server by means of generated ABAP Objects classes.

4.3.1.2 Rule

Use Web Dynpro ABAP

Page: 116 of 227


Use Web Dynpro ABAP whenever possible to create the UIs of new application programs.

4.3.1.3 Details

Web Dynpro ABAP is SAP's standard UI technology for developing modern Web applications in the ABAP
environment. The MVC approach automatically ensures a separation of presentation logic and application logic,
based on the SoC principle.

Compared to Web Dynpro, the BSP technology is much more fundamental. An MVC approach for the SoC is
supported, but developers are still responsible for the implementation. BSPs can be regarded as the
predecessor technology of Web Dynpro ABAP. The use of BSPs is now restricted to cases where a Web
application is based on a single HTML page, for which scripting is required and the function cannot be
implemented with Web Dynpro ABAP.

The classic SAP UI technology # classic dynpros based on the SAP GUI, including selection screens and lists #
is no longer sufficient for modern and flexible business applications where the user interface must be accessible
in a portal, for example. The MVC approach is not supported by frameworks or by any relevant tools.
4.3.1.3.1 Exception

The various UI technologies are not interoperable. In other words, it is usually not possible to switch parts of an
application based on classical dynpros (including selection screens and classic lists) to Web Dynpro ABAP. In
addition, the commonly implemented dynpro programming model was previously not very oriented toward SoC.
This makes it difficult or even impossible to implement a changeover for the purpose of further development.
Consequently, in exceptional cases, classic dynpros and/or selection screens might be required if a new
development needs to be included in an existing framework. For these exceptional cases, the following rules
have been devised to ensure that these obsolete UI technologies are handled using a more modern approach.

4.3.1.3.2 Note

In general, you can replace the UI technology of an application that is strictly modeled on the separation of
concerns (see example below).

4.3.1.3.3 Note

Web Dynpro ABAP itself is not part of the ABAP language. Specific guidelines regarding the use of Web Dynpro
ABAP are not covered by these programming guidelines, which mainly focus on using the ABAP language to
implement services.

4.3.1.3.4 Example

The transaction DEMO_CR_CAR_RENTAL is called. Now two user interfaces can be selected for a car rental
example:

• A UI based on classic dynpros and selection screens. However, according to the above rule, using this
UI technology in application programs is no longer recommended.

• A modern UI based on Web Dynpro ABAP

Since the sample application strictly separates all concerns, you can use it with different UIs, without having to
make adjustments to the application and persistency logic. The SoC is therefore a critical prerequisite for
potential changeovers from classic dynpros to Web Dynpro ABAP.

Page: 117 of 227


Encapsulating Classical User Interfaces

4.3.2.1 Background

The separation of concerns is one of the basic rules of these ABAP programming guidelines. This separation,
which refers to a strict division of ABAP code into parts for presentation services, application services, and
persistency services, is also technically possible for classical dynpro-based UI technologies. The MVC
approach is not directly supported, but SoC can also be achieved though the consistent use of the available
encapsulation technologies.

However, SoC was rarely implemented in classical dialog programming. Here, presentation logic, application
logic, and persistency logic were often combined in a monolithic module pool.

4.3.2.2 Rule

Encapsulate classical dynpros and selection screens


Only create classical dynpros and selection screens in the presentation layer programs specifically provided for
this purpose. You can use function groups as the program type.

4.3.2.3 Details

When using classical UI technologies, you need to separate the display logic from the application logic for the
following reasons:

• Reuse individual components

• Automated program logic tests, irrespective of the UI

• Change the UI technology

In addition, the communication between classical dynpros/selection screens and ABAP programs is
implemented using global variables. This poses conceptual problems and cannot be combined with a modern,
object-oriented approach for application programs.

Since class pools do not support classical dynpros and selection screens, you can only use function groups for
encapsulation. In this role, a function group must be considered a global class. Here, the data of the global
declaration part assumes the role of the private attributes, and the function modules assume the role of the
public methods. The relevant procedure is demonstrated in DEMO_CR_CAR_RENTAL_SCREENS of package
SABAP_DEMOS_CAR_RENTAL_DYNPRO. It applies to selection screens.

Besides UI elements, these function groups can only contain display logic in the form of local classes. The
application logic communicates with the display logic using the function modules of this function group. You can
still call the first dynpro of a dynpro sequence using a transaction code. This method is used in cases where the
user starts the application.

The guidelines described in this book are also valid in function groups. It is especially important that the dialog
modules (PBO and PAI), which are called by the dynpro, or the event blocks for selection screen processing do
not contain any program logic. Instead they should directly delegate the processing to the relevant methods of
the local classes. The same applies to the function modules that act as the external interface. In addition, you
must restrict the scope of the function group global data to the minimum scope required for communicating with
dynpros.

4.3.2.3.1 Exception

Page: 118 of 227


Following the above rule means you cannot use standard selection screens. Therefore, it is necessary to
make an exception to this rule for executable programs that are executed during background processing. This
is because the required parameter interface must be a standard selection screen defined directly in the
program. An encapsulation in a function group is not possible here. However, in this case, the events of
selection screen processing should only call one appropriate method of a local class within the executable
program. 4.3.2.3.2 Bad example

A classic dialog program - usually a single module pool - processes all the facets of an application.

4.3.2.3.3 Good example

The following source text shows a part of a function group DEMO_CR_CAR_RENTAL_SCREENS with
expanded include programs. This function group encapsulates the dynpro and selection screen for transaction
DEMO_CR_CAR_RENTAL, following the above rule. The connection to the application layer is established
exclusively using the if_demo_cr_car_rentl_service interface, which is also used in the Web Dynpro application
of this transaction.
FUNCTION-POOL demo_cr_car_rental_screens.
* Top Include
SELECTION-SCREEN BEGIN OF SCREEN 200 TITLE text-ccr.
PARAMETERS g_name TYPE demo_cr_customer_name. SELECTION-
SCREEN END OF SCREEN 200.
TABLES demo_cr_scustomer_cntrl.
CONTROLS: customers TYPE TABLEVIEW USING SCREEN 0100,
reservations TYPE TABLEVIEW USING SCREEN 0100.
DATA g_ok_code TYPE sy-ucomm.
DATA: g_customers TYPE TABLE OF demo_cr_scustomer_cntrl,
g_customer LIKE LINE OF g_customers.
DATA: g_reservations TYPE TABLE OF demo_cr_sreservation_cntrl,
g_reservation LIKE LINE OF g_reservations.
* Local Class Declarations
CLASS screen_handler DEFINITION.
PUBLIC SECTION.
CLASS-DATA car_rental_service
TYPE REF TO
if_demo_cr_car_rentl_service. CLASS-
METHODS: class_constructor,
status_0100, user_command_0100,
cancel.
PRIVATE SECTION.
CLASS-METHODS: customer_search_by_id,
...
ENDCLASS.
CLASS customer_table DEFINITION.
PUBLIC SECTION.
CLASS-METHODS: change_tc_attr,
mark.
ENDCLASS.
...
* Function Module
FUNCTION demo_cr_call_car_rental_screen.
CALL SCREEN 100.
ENDFUNCTION. *
PBO Modules
MODULE status_0100 OUTPUT.
screen_handler=>status_0100( ).
ENDMODULE.

Page: 119 of 227


MODULE customers_change_tc_attr OUTPUT.
customer_table=>change_tc_attr( ).
ENDMODULE.
...
* PAI Modules
MODULE cancel INPUT.
screen_handler=>cancel( ).
ENDMODULE.
MODULE user_command_0100 INPUT.
screen_handler=>user_command_0100( ). ENDMODULE.
MODULE customers_mark INPUT.
customer_table=>mark( ).
ENDMODULE.
...
* Local Class Implementations
...
Dynpro 100 is called in a function module but can also be linked to a transaction code. In the classical PBO and
PAI modules, methods of local classes are called. However the implementation of these methods is not shown
here. There is a class for general screen handling and a class for each table control. The application layer is
accessed using the specified interface for implementations of the class.

Lists

4.3.3.1 Background

A list is a medium used for the structured and formatted output of data. The following lists are available in
ABAP:

• Classical lists, which are written to a list buffer using ABAP statements and displayed on a special list
dynpro.

• Output of the SAP List Viewer (ALV), which is displayed in GUI controls during the processing of
classical dynpros. ALV lists are accessed using classes, such as CL_SALV_TABLE (non-hierarchically
tabular lists), CL_SALV_HIERSEQ_TABLE (hierarchically sequential lists), or CL_SALV_TREE
(hierarchically tabular lists).

Classical lists are the only option to send ABAP data from ABAP programs directly to the SAP spool system as
print lists. If SAP List Viewer is used, the lists that are displayed in the viewer are automatically converted to
classical print lists during printing.

4.3.3.2 Rule

Use SAP List Viewer

Do not use classical lists. If dynpro-based, classical UI technologies are still used, SAP List Viewer (ALV) or
other GUI control-based technologies should be used instead of classical lists in production programs.

4.3.3.3 Details

Using classical lists is no longer recommended for the following reasons:

Page: 120 of 227


• The processing of lists is based on global data and events of the ABAP runtime environment.

• The list buffer that is used for classical lists is bound to an executable program or a dynpro sequence
and not to classes and objects.

• It is almost impossible to separate presentation logic and application logic when writing to lists.

• The UI of a classical list is not standardized and thus usually not accessible.

The concept of classical lists is therefore mostly incompatible with the ABAP Objects concept, and classical lists
cannot be encapsulated in function groups as easily as classical dynpros and selection screens.

While the application developer must ensure accessibility in classical lists with a great deal of effort, the ALV
lists automatically comply with the accessibility requirements because the ALV already provides the required
services, such as user-specific settings.

4.3.3.3.1 Exception

Small helper programs that are not intended for live use in application systems can continue to use classical
lists
for system-related console output. The WRITE list statement here assumes the same role as
System.out.println(...) in Java or printf in C.

In cases in which an ALV output seems to be overdimensioned, other methods are possible, such as Textedit
Control or Browser Control (or its wrapping in dynamic documents) for the formatted output of non-tabular
content. As before, accessibility must be guaranteed here.

4.3.3.3.2 Note

For simple console output, XML-based output streams can also be used. An example of this is shown by the
class CL_DEMO_OUTPUT_STREAM. The class CL_DEMO_OUTPUT demonstrates possible applications of
this class. It is used in programs in the ABA Example Library.

4.3.3.3.3 Bad example

Executing the program DEMO_CLASSICAL_REPORTING produces a classical list output. However, according
to the above rule, using classical lists in application programs is no longer recommended.

4.3.3.3.4 Good example

Executing the program DEMO_ALV_REPORTING produces ALV lists with the same content and the same
functions as the classical lists in the previous example. ALV lists replace classical lists in those cases in which
classical dynpros are still used.

Accessibility

4.3.4.1 Background

Accessibility is a product standard that ensures that information technology products can also be used by
people with impairments. For user interfaces, for instance, this means meeting the needs of visually impaired or
blind users in particular. These users usually need a screen reader program, which reads the content of the
screen aloud.

Page: 121 of 227


4.3.4.2 Rule

Ensuring Accessibility

Make sure that your user interfaces are accessible, no matter what interface technology is used, so that they
can be used by users with impairments.

4.3.4.3 Details

Primarily, user interfaces must be designed so that they can be processed by technologies such as screen
readers or magnifiers. This means meeting the following requirements:

• All input and output fields must have meaningful labels.

• All table columns must have a header.

• All icons must have a quick info.


• 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.

This is another reason to use the most up-to-date interface technologies, such as Web Dynpro ABAP or ALV.
These automatically only allow accessible interfaces, whereas application developers using older technologies
such as classic screens or classic lists are themselves responsible for ensuring that the accessibility
requirements are met. There are some checks in the check tools for classic screens and selection screens that
report violations of these rules (if they can be identified statically). However, for classic lists such checks are not
possible until display.

4.3.4.3.1 Note

As regards using the browser control in classic screens, we refer here to the class CL_HTMLTIDY. This class
enables you to check HTML files for formal correctness and accessibility. We recommend that you only display
HTML files in a browser control if they have been checked by CL_HTMLTIDY. The class
CL_ABAP_BROWSER, which wraps the browser control for simple displays of HTML files, performs a check
with CL_HTMLTIDY by default.

4.4 Data Storage


ABAP programs generally work with data imported from persistent memory media to the internal session of the
current program execution. This data is then available to the program as transient data. For performance
reasons, data can also be stored in the shared memory of the current application server. This shared memory is
available to all programs of an application server. Access to data in the shared memory is faster than accessing
data in persistent memory media by some magnitude.

Persistent Data Storage

4.4.1.1 Background

ABAP programs can have both read and write access to data in the following persistent storage media:

Page: 122 of 227


• Relational database tables in databases

• Data clusters in special database tables

• Binary files or text files on the application server

• Binary files or text files on the PC if SAP GUI is used

According to the SoC principle, such accesses are wrapped in service classes of the persistency layer of an
application.

4.4.1.2 Rule

Plan persistent data storage carefully


Select with care the persistent storage media that are used by the application as well as the possible data
transport routes between these media. Here is a general rule of thumb:

• Database tables for the general storage of raw data

• Data clusters for the storage of formatted data

• Files for data exchange with external systems

4.4.1.3 Details

When you plan persistent data storage, you should follow these steps:

1. On an AS ABAP, storing in relational database tables is always the first choice. ABAP supports this
with the Open SQL that is integrated into the language. An object-oriented access is possible using
Object Services. The majority of the data is stored in the central standard database of the application
server. You can access additional databases by using secondary database connections (managed
using the DBA Cockpit).
2. The following data can be stored in data clusters when using the EXPORT and IMPORT statements: -
Formatted data as the result of comprehensive analyses
- Data that is not suitable for relational databases because it does not exist in the first normal form
(such as nested internal tables)
- Object networks after a serialization to XML
3. The persistent storage of data in files of the application or presentation server is usually the least
suitable for AS ABAP application programs because it is generally platform-dependent (codepages,
byte order). In addition, such data is then only available on a particular application server, which can be
problematic in a load distribution scenario with automated server selection. Such files may be required
for the data exchange with external systems, however.

Under no circumstances should you use existing database tables (or files) to store data that are not provided for
this purpose. Follow the convention of restricting reads and writes to database tables to specific packages. A
database table must always be considered a semantic entity that is only allowed to contain the corresponding
data. This even applies if a table with the required structure already exists. If in doubt, you should create a
specific database table.

You must also be careful when using seemingly cross-system resources, such as the predefined INDX
database table, to store data clusters. Such a resource must only be used to store temporary data for the short
term, if at all. You should create specific database tables, for example, INDX-type tables, for application-specific
and longer-lasting data.

Page: 123 of 227


Databases Accesses

4.4.2.1 Background

In ABAP, data in database tables can be accessed in the following ways:

• Open SQL
Implemented by ABAP statements, this is a subset of the Structured Query Language (SQL) comprising
the DML (Data Manipulation Language) part. The statements of Open SQL use the Open SQL interface
to access, independently of the platform, the database tables of the database of an AS ABAP that are
defined in the ABAP Dictionary.
• Native SQL
Database-specific SQL statements that include both DML and DDL (Data Definition Language)
statements and which can be passed to the Native SQL interface of the database as follows:

o The methods of ADBC make it possible to execute dynamic SQL statements on a database system
and process the results. ADBC (ABAP Database Connectivity), a class-based API that enables
object-oriented access to the Native SQL interface.

o The AMDP framework is used to manage and call ABAP Managed Database Procedures. These
are stored procedures or database procedures implemented as AMDP procedures in an AMDP
method of an AMDP class and replicated to the database system from here.

o Native SQL statements can be specified in ABAP programs between the statements EXEC SQL
and ENDEXEC. Static Native SQL statements of this kind are not checked completely by the
syntax check and are forwarded almost unchanged from the Native SQL interface to the database
of an AS ABAP.

All access types (with the exception of AMDP) also enable access to other databases using additional
connections (except for access to the central database of an AS ABAP (standard connection)).

4.4.2.1.1 Note

For calls of database procedures of an SAP HANA database, there is also the statement CALL DATABASE
PROCEDURE, which is particularly well suited to access using a secondary database connection.

4.4.2.2 Rule

Using Open SQL

Use Open SQL for general persistence services where possible. Only use Native SQL for tasks where Open
SQL is not suitable.

4.4.2.3 Details

Only Open SQL is guaranteed to be independent of the database platform used. For this reason, Open SQL
does not contain the set of all possible SQL statements in a specific database, but only a subset of the DML
scope of all database systems supported by AS ABAP. The database tables that can be processed using Open
SQL can be used in ABAP directly as structured types for the declaration of suitable work areas. Only Open
SQL supports SAP buffering of table content in the shared memory.

Native SQL should only be used if the task really cannot be solved using Open SQL. Services that work with

Page: 124 of 227


Native SQL are generally dependent on the database system used, so that they cannot be executed in all AS
ABAP systems. For platform-independent services, implementations should be provided for all supported
databases.

If the database is accessed using the Native SQL interface instead of the Open SQL interface, ADBC or AMDP
should be used.

• ADBC is a modern object-oriented API that is better suited to modern ABAP programming than EXEC
SQL. Enhancements to the Native SQL interface, such as bulk access using internal tables, are now
only provided using ADBC. ADBC also enables dynamic access; Native SQL on the other hand is just
static.

• AMDP, currently only available for the central SAP HANA database of an AS ABAP, is recommended for
all tasks that swap out code from ABAP programs to this SAP HANA database for performance
reasons.
4.4.2.3.1 Note

The rule dictating that Open SQL is to be used for as long as possible applies in particular to AMDP too. It is not
a good idea to swap out SQL statements to database procedures if these could be implemented using Open
SQL or ABAP CDS too. In this case, no performance gains can be expected since the Open SQL statements
are updated to Native SQL by the database interface in exactly the same way as they would be written in the
database procedure. Using AMDP is a good idea only if HANA-specific properties can be exploited by
procedure calls or if repeated transports of large amounts of data between the database and the application
server can be bypassed.

4.4.2.3.2 Bad example

See AMDP, Comparison with Open SQL. A database access not programmed well using Open SQL can often
be optimized by improved use of Open SQL, making it unnecessary to use AMDP in these cases.

4.4.2.3.3 Good example

See Currency Conversion with SQLScript. In this case, a specific operator of the language SQLScript is used
that is not usually available.

Client Handling

4.4.3.1 Background

A client indicates a data area in an AS ABAP database that contains independent application data. The
application data of different clients use the same database tables, but are flagged with a three-figure client ID
within these tables.

When logging on to AS ABAP, this client ID must be entered. This selects the client whose data is processed by
the user session. The current client is entered in the system field sy-mandt.

• Open SQL statements support automatic client handling by default, where the data of the current client
is accessed by default. This is specified by passing an implicit condition for the current client to
WHERE conditions, and ignoring clients specified in modifying statements in work areas. Automatic
client handling in Open SQL can be switched to a different client using the addition USING CLIENT or
switched off using the addition CLIENT SPECIFIED.

Page: 125 of 227


• Native SQL does not implement automatic client handling. The client in question does not need to be
selected explicitly when Native SQL is used to access client-specific database tables or views.

4.4.3.2 Rule

Do not access the data of other clients

In the persistency services of business applications, access the data of the current client only.

4.4.3.3 Details

Each client within the application server is to be viewed as a self-contained unit. The additions USING CLIENT
and CLIENT SPECIFIED should not be used in Open SQL statements of business applications. When Native
SQL is used, only the current client should be selected.
The system field sy-mandt does not generally need to be evaluated, unless Native SQL is used to access
clientspecific database tables or views. The client ID is then needed to select the data of the current client
explicitly.

4.4.3.3.1 Notes

• Cross-client database tables (tables without client ID) are usually system tables. This means that
crossclient access to these tables is also reserved for system programs.

• If Open SQL has to be used to access data in a different client, USING CLIENT should be used
instead of the addition CLIENT SPECIFIED, since all necessary conditions are set implicitly and
accessing client-specific CDS views is more simple.

4.4.3.3.2 Bad example

The following source code shows an Open SQL access to a database table where the current client is specified
explicitly. This makes a further explicit WHERE condition necessary. The system field sy-mandt cannot be
specified directly when using the addition USING CLIENT.

SELECT SINGLE ...


FROM dbtab CLIENT SPECIFIED
WHERE mandt = @sy-mandt AND
...
INTO ...

4.4.3.3.3 Good example

The following source code shows how Open SQL is generally used for implicit automatic client handling.

SELECT SINGLE ...


FROM dbtab
WHERE ...
INTO ...

Using Shared Memory

4.4.4.1 Details

Page: 126 of 227


For explicit access to the shared memory, shared objects (CREATE AREA HANDLE) provide the following
advantages compared to the cross-transaction application buffer (SHARED MEMORY, SHARED BUFFER):

• Any number of (data) objects can be saved, including their mutual interdependencies.

• (Data) objects can be used in the shared objects memory just like objects in the internal session.
Technically, the shared objects memory can be considered an extension of the internal session during
the time the memory is bound to it.

• Multiple programs can access the same memory area simultaneously without having to copy data to
their own internal session.

Scenarios in which shared objects can be used efficiently include the following:

• Usage as a shared buffer


A shared buffer contains a large data set to which many users have read access but which is changed
rarely and is usually provided by a single program.
• Usage as an exclusive buffer
An exclusive buffer contains data that are accessed by only one program but that is maintained for
various programs across transaction boundaries.

The shared memory should not be used for different purposes, if, for example this results in many modifying
accesses of parallel users, as the current locking concept does not support this.

Access to the shared memory should be encapsulated in specific classes, and application programs should
access the shared memory using these classes only. Normally, there are two classes, which can also be
combined into one class:

• A loader for creating and changing area instances

• A broker for read access to area instances

Such wrapping ensures the following:

• Central management of the internal session’s connection to the shared objects memory and the
associated locks

• Central exception handling and respective fallback strategies (for example, if the shared object’s
memory overflows, it is possible to ensure that objects in the internal session are used without the
using program having to be notified of this).

• Potential authorization checks

This makes the application program more legible, more robust, and easier to maintain.

4.4.4.1.1 Bad example

The following source code shows how an internal table index_table, which has been formatted elsewhere and
buffered in the cross-transaction application buffer, is imported to a program. To store it locally, a local data
object is required. Tasks like these can be performed more efficiently by using shared objects.

"Get index page from data cluster


IMPORT index_html = index_html
FROM SHARED MEMORY docutables(...) ID ...

Page: 127 of 227


ASSERT sy-subrc = 0.

4.4.4.1.2 Good example

The following source code shows how an internal table index_table, which has been formatted elsewhere and
buffered in the shared objects memory, can be accessed within program. By calling a get method, the
corresponding broker ensures that its root attribute refers to a shared object that contains the table. A local data
object is then not required to access the internal table in the program.

"Get index page from shared memory


cl_docu_tables_broker=>get_index_table( ).
ASSERT cl_docu_tables_broker=>root->index_html
IS NOT INITIAL.

Using Shared Objects

4.4.5.1 Background

Access to shared objects is regulated by lock mechanisms. The individual locks are stored as administrative
information with the area instances in the shared memory and are set and evaluated when they are accessed
using area handles.

4.4.5.2 Rule

Shared buffer and exclusive buffer are suitable application scenarios for shared objects.

The access to shared objects should be wrapped in loader and broker classes.

4.4.5.3 Details

How locks work depends on how shared objects are used as follows:

• Scenario 1 - Use as a shared buffer

A shared buffer is a data store that is rarely changed (once a day up to a maximum of once an hour),
usually by a single user only. The amount of data can be very large. In general, many users have read
access to a shared buffer at the same time. A typical use of a shared buffer is to store a catalog.

• Scenario 2 - Use as an exclusive buffer

An exclusive buffer is a data store that is read or write accessed by one user only, or in rare cases, by
one user with write access and another with read access. The data stored in an exclusive buffer should
be available longer term, that is, longer than a program’s lifetime. A typical use of an exclusive buffer is
to store a shopping basket that is filled initially by the shopper and then read by the salesperson later.

General shared memory programming is not possible. The current lock logic does not enable you to set specific
locks for the following requirements:

• Many parallel read and write accesses

• Frequent write accesses

• Division into changeable and non-changeable areas

Page: 128 of 227


Although the lock logic makes the first two points technically possible, they are not practical because most
accesses would be rejected.

4.4.5.3.1 Wrapping

It is recommended that application programs do not access the shared objects memory directly. Instead (read)
accesses to the shared objects should be wrapped in a wrapping class, whose methods are accessed by the
individual programs. The area constructor class can be used as the wrapping class, for example.

Wrapping has the following advantages:

• Central administration of an area in the shared memory


• An application program does not need to worry about area handles and locks.

• Central administration of locks

• Option to implement central authorization checks

Page: 129 of 227


5 ROBUST ABAP
The recommendations and rules explained in this section are intended to help you create reliable and robust
ABAP programs, which behave as expected for both the developers and the program maintenance technicians.

5.1 Data Types and Data Objects


Together with classes and objects, data types and data objects are the essentials of ABAP programming.

• Data type

A data type describes a data object, just as a class describes an object. In this sense, a data
type is comparable with a class without methods. ABAP interprets the content of a data object in
accordance with its data type. Data types exist either bound as a property of data objects or
independently. Independent data types can be defined either in ABAP Dictionary or using the TYPES
statement in an ABAP program.

• Data object

A data object is an instance of a data type, just as an object is an instance of a class. It exists in
the internal session of an ABAP program or as a shared object in the shared memory and occupies
memory there for the contained data. A data object is generated either implicitly when a program or
procedure is loaded (named data object), or by using the CREATE DATA statement (anonymous data
object). Named data objects are either variables (DATA, CLASS-DATA statements, and so on) or
constants (CONSTANTS statement).

A data type describes the technical properties of a data object (for example, the elementary types it is
comprised of, its length) and semantic properties (what type of entity is represented by the data object). Types
that are defined in ABAP dictionary have additional properties, for example for input/output on a classic dynpro
or in Web Dynpro.

As far as the ABAP runtime environment is concerned, only the technical properties of a data object are of
interest for program execution. However, the semantic information, which is linked to the appropriate use of
types, is essential for the legibility of the source code. For this reason, some of the rules covered in this section
could also fall under the heading Structure and Style, since this covers not only robustness, but also good style,
which, although it does not affect program execution, is nevertheless significant for readability and
maintainability.

Bound and Standalone Data Types

5.1.1.1 Background

A bound data type only exists as a property of a data object. It is created if a data object is not declared with
reference to a standalone data type that defines all technical properties but if technical properties are defined in
the DATA statement. Here DATA is used as a synonym for all statements that declare data objects. The
resulting type is a property of the declared variable and it is bound to this variable. If this type is needed in
several different places, it has to be defined separately for each place where it is used.

A standalone data type is declared in the ABAP Dictionary or using the TYPES statement and defines all
technical properties of a data object with one exception: When table types are defined, they can be generic with
regard to key specification. A standalone generic type can only be used for typing but not for data declarations.
However, there is one exception: In a DATA statement, the standard key is added to the generic standard table
type.

Page: 130 of 227


5.1.1.2 Rule

Use standalone data types

Use standalone data types instead of constructing bound data types when declaring data objects.

5.1.1.3 Details

Here is a list of reasons that support the declaration of standalone types:

• The declaration of a standalone data type allows multiple data objects (or interface parameters or field
symbols) to use a type without the need to always redefine this type.

• Even if only one data object of this type is required initially, it is very likely that further data objects will
be added during the course of the development. If the type needs to be adapted later on, you can do
this centrally.

• Declaring a standalone type and using it to declare a data object is nothing more than following the rule
for the SoC principle.

The data type should always have a specific meaning and a meaningful name. This gives data types a clear
semantic meaning and makes the program easier to read and understand. Therefore, you should declare
different data types for technically identical but semantically different data objects. This also increases the
probability that a type can be adapted later on without making major program changes.

Therefore you should avoid declaring purely technical data types that cannot be associated with specific
semantics, because this does not make it easier to read or enhance the program.

5.1.1.3.1 Note

A separate rule specifies where the standalone data types should be declared.

5.1.1.3.2 Bad example

The following source code shows the declaration of two data objects that are supposed to have the same data
type. However, the technical properties, length, and number of decimal places are defined as independent,
bound data types in the various DATA statements.

...
DATA number_1 TYPE p LENGTH 6 DECIMALS 2.
DATA number_2 TYPE p LENGTH 6 DECIMALS 2.
...

5.1.1.3.3 Good example

The following source code outsources the definition of the technical properties of the data objects in the above
example to a separate TYPES statement. The standalone data type is only declared once and can then be
used multiple times.

TYPES number_type TYPE p LENGTH 6 DECIMALS 2.


...
DATA: number_1 TYPE number_type,
number_2 TYPE number_type.
...

Page: 131 of 227


Declaration of Data Types and Constants

5.1.2.1 Background

Data types and constants can be declared in the following contexts:

• Cross-program o in the ABAP Dictionary o in global classes and

interfaces o in type groups

• Local program o in the global declaration part of a program o in global

classes and interfaces o in procedures (Methods)

Technically speaking, type groups, global classes and interfaces are also ABAP programs, in which data types
and constants are created using the TYPES and CONSTANTS statements. In contrast to other ABAP
programs, the declarations can also be statically visible in other programs, depending on the visibility section.
Absolute type names enable you to dynamically access the types of all programs.

5.1.2.2 Rule

Declare data types and constants in the appropriate context

Declare data types and constants in the context that guarantees the best possible encapsulation.

5.1.2.3 Details

Data types and constants should be declared in the context, in which they are visible for all potential users but
not anywhere else:

• Local program data types and constants

o Data types that are only required by local data objects (usually helper variables) or constants that
are only required in a procedure (method) should be declared as local data types or constants.

o Data types and constants that are only required within local classes should be declared in the
corresponding visibility section of the classes or integrated using an interface.

o If data types are required in multiple local classes and interfaces of a program, they should be
created in the appropriate visibility section of a local class or an interface. Local classes or
interfaces can be used that contain nothing else apart from these types or constants. In the global
declaration part of programs, declarations of data types or constants are not required for semantic
reasons.

• Cross-program data types and constants


o Date types and constants, that a user requires to use a class/interface, should be declared in the
public (or package-public) visibility section of the global class/interface. Examples include data
types used to type interface parameters of methods, and constants expected as actual parameters
by methods, such as IDs of exception texts in exception classes.

Page: 132 of 227


o Data types required by different programs, classes, or interfaces are declared as real types of the
ABAP Dictionary (not in type groups). These are usually semantically independent types, for which
the ABAP Dictionary provides additional services, such as descriptive texts and documentation
options. In this context, you must consider the separation of concerns.
For example, a structure of the ABAP Dictionary should never be used to type (Web) Dynpro
fields and to simultaneously define a database table. Ideally, data types should be declared in
encapsulated packages, which manage the cross-package use of their repository objects and
which only expose types actually required outside the package in their package interfaces. You
should generally avoid declaring or even exposing purely technical types without semantic
meaning, in application development packages of the ABAP Dictionary. The declaration of these
types (such as INT2 or CHAR10) should be restricted to fundamental basis packages.

o You should not create any new type groups. Data types should be declared in global classes or
interfaces, or as real types of the ABAP Dictionary. You should only create constants in global
classes or interfaces. However, the use of existing type groups is still allowed. It is no longer
necessary to load type groups explicitly using the TYPE-POOLS statement. However, you only
need to declare new types or constants in a context, if no semantically appropriate types or
constants exist that are more global. For example, if an appropriate ABAP Dictionary data type
exists, it is not necessary to create a local data type in the class, to type an interface parameter of
a global class method. In this case, the data type in the ABAP Dictionary might have to be
published in the same package interface as the class. This would also be the case, however, if an
interface parameter is typed with a data type of the class that refers to an ABAP Dictionary data
type.

5.1.2.3.1 Note

The misuse of include programs for the declaration of data types and data objects that can be reused across
various programs is not allowed.

5.1.2.3.2 Bad example

The following source code shows the declaration of constants in a type group that are required across different
programs. The name of the type group must precede the names of the constants as a prefix. You should not
create any new type groups. For constants that are required in various different programs, the above rule
recommends a declaration in global classes or interfaces.

TYPE-POOL zicon.
TYPES zicon_icon TYPE ...
CONSTANTS:
zicon_cancel TYPE zicon_icon VALUE icon_cancel,
zicon_check TYPE zicon_icon VALUE icon_check,
zicon_check_words TYPE zicon_icon VALUE icon_intensify,
zicon_document TYPE zicon_icon VALUE icon_hlp,
zicon_download TYPE zicon_icon VALUE icon_export,
...

5.1.2.3.3 Good example

The following source code illustrates the declaration of the constants in the above example in a global class.
The visibility of the constants is restricted to the current package. In other programs, the constants are
addressed using cl_..._icons=>.

CLASS cl_..._icons DEFINITION PUBLIC FINAL.


PUBLIC SECTION.
TYPES icon TYPE ...
CONSTANTS cancel TYPE icon VALUE icon_cancel.
CONSTANTS check TYPE icon VALUE icon_check.

Page: 133 of 227


CONSTANTS check_words TYPE icon VALUE icon_intensify.
CONSTANTS document TYPE icon VALUE icon_hlp.
CONSTANTS download TYPE icon VALUE icon_export.
...
ENDCLASS.

Declaration of Variables

5.1.3.1 Background

Variables can be declared in the following contexts:

• Cross-program: as attributes of global classes and interfaces

• Program-local:

o in the global declaration part of a

program o As attributes of local classes

and interfaces o In procedures (Methods)

Variables that are declared within most of the event blocks or dialog modules as well as between completed
processing blocks also belong to the global declaration part of a program, but violate the rule implement global
declarations centrally.

Program-local variables that are declared in the global declaration part of a program are generally referred to as
global variables.

5.1.3.2 Rule

Do not declare global variables

Do not declare variables in the global declaration part of a program. Variables may only be declared as
attributes of classes and interfaces or locally in methods.

5.1.3.3 Details

This rule is directly derived from the basic rule use ABAP objects. If you disregard helper variables in
procedures (methods), the content of the variable of a program indicates the state of the program and
consequently the state of an application. In object-oriented programming, the class replaces the program, and
the state of an application is no longer the state of the programs but the state of the classes or objects.

Furthermore, the rule exploit the benefits of encapsulation also assumes a critical role. The data of an
application is sufficiently protected from misuse only in the visibility sections of classes.

Except for the following exception, you should not declare any global variables in a new ABAP program. They
indicate a poor programming style that disregards proven concepts such as task sharing and encapsulation. If
you need to access the same data of a program from multiple local classes and interfaces, you must create
them in an appropriate visibility section of a local class or an interface. These can also be local classes or
interfaces that contain nothing but such attributes.

Page: 134 of 227


5.1.3.3.1 Note

The above rule also applies to the declaration of field symbols with the FIELD-SYMBOLS statement.

5.1.3.3.2 Exception

If you still use classical dynpros and selections screens instead of Web Dynpro ABAP, global variables are
required as interfaces for the communication between ABAP and classical dynpros. Global variables can be
declared using the following statements for this purpose alone:

• DATA, TABLES and CONTROLS for general dynpros

• PARAMETERS and SELECT-OPTIONS for selection screens

In these cases, you have to ensure the maximum possible encapsulation of those global variables.

5.1.3.3.3 Bad example

The following source code shows the top include of a function group for document display. In addition to the
required interface work area, which is declared with TABLES, further global variables exist that indicate the
state of the display. However, according to the above rule, you are not allowed to use global variables for
purposes other than communication with a classical dynpro.

FUNCTION-POOL show_documents.
TABLES document_structure. DATA:
g_language TYPE sy-langu,
g_display_mode TYPE ...
...
CLASS screen_handler DEFINITION.
PUBLIC SECTION.
...

5.1.3.3.4 Good example

The following source code shows an improved example. The previously global variables are encapsulated in a
class that is specifically provided for the state of the display, and can be addressed using display_status=> in
the other classes of the program.

FUNCTION-POOL show_documents.
TABLES document_structure.
CLASS display_status DEFINITION.
PUBLIC SECTION.
CLASS-DATA: language TYPE sy-langu,
display_mode TYPE ...
...
ENDCLASS.
CLASS screen_handler DEFINITION.
PUBLIC SECTION.
...

Inline Declarations

5.1.4.1 Background

The declaration operators

Page: 135 of 227


• DATA(var)

• FIELD-SYMBOLS <fs>.

can be used to make inline declarations in writer positions. In this way, declarations are made in operational
statements rather than in declaration statements. The declaration is made when the program is compiled,
regardless of whether the statement is actually executed.

5.1.4.2 Rule

Only use inline declarations locally

Only make inline declarations in processing blocks that support local data. Use them as if they were local
declarations in the current statement block.

5.1.4.3 Details

If used correctly, inline declarations are an excellent way of making programs leaner and easier to understand.
An inline declaration in a statement functions like a short form of a declaration statement directly in front of the
statement, which is why the guidelines for declaration statements must be followed:

• The rule dictating that no global program variables and field symbols are to be declared also applies to
inline declarations, without restrictions. For this reason, statements with inline declarations should only
be specified in processing blocks with local data, namely procedures and preferably methods. If not,
the variables and field symbols declared inline would be global in the program, with all the drawbacks
listed in the description of the rule.

• Inline declarations are an exception to the rule that local declarations should only be made at the start
of a procedure. They are specified in operational statements, which means that, unlike declaration
statements, they cannot be specified at the start of the procedure. Despite this, the restrictions stated in
the rule for local declarations are still valid for inline declarations. In particular, the validity of inline
declarations is not limited to their current statement block. Inline declarations should, therefore, only be
specified in less complex procedures, so making them easier to understand. The variables and field
symbols declared inline should only be used in the direct vicinity of their declaration. Under no
circumstances should a variable declared inline be accessed dynamically before the declaration. When
an inline declaration is specified in a (conditional) control structure, it should usually only be accessed
within this statement block.

5.1.4.3.1 Bad example

Inline declaration of a field symbol <pattern> and two variables moff and mlen in a LOOP and their later reuse in
a different loop. At first glance, it appears that the declarations are only valid in the first loop and only
conditionally, but they are valid for the whole method and unconditionally.

METHOD demo_method.
"IMPORTING i_tab1 TYPE TANDARD TABLE OF string
"IMPORTING i_tab2 TYPE TANDARD TABLE OF string
"IMPORTING i_text TYPE string

IF i_tab1 IS NOT INITIAL.


LOOP AT i_tab1 ASSIGNING FIELD-SYMBOL(<pattern>).
FIND <pattern> IN i_text MATCH OFFSET DATA(moff)
MATCH LENGTH DATA(mlen).
...
ENDLOOP.

Page: 136 of 227


ENDIF.

IF i_tab2 IS NOT INITIAL.


LOOP AT i_tab2 ASSIGNING <pattern>.
FIND <pattern> IN i_text MATCH OFFSET moff
MATCH LENGTH mlen.
...
ENDLOOP.
ENDIF.

ENDMETHOD.

5.1.4.3.2 Good example

The field symbols and variables declared inline are only used locally in the their respective loops. The fact that
they are valid in the whole method is ignored, for the sake of simplicity. If the field symbol and the variables are
only to be declared once for both loops, they should be declared at the start of the method using declaration
statements.

METHOD demo_method.
"IMPORTING i_tab1 TYPE TANDARD TABLE OF string
"IMPORTING i_tab2 TYPE TANDARD TABLE OF string
"IMPORTING i_text TYPE string

IF i_tab1 IS NOT INITIAL.


LOOP AT i_tab1 ASSIGNING FIELD-SYMBOL(<pattern1>).
FIND <pattern1> IN i_text MATCH OFFSET DATA(moff1)
MATCH LENGTH DATA(mlen1).
...
ENDLOOP.
ENDIF.

IF i_tab2 IS NOT INITIAL.


LOOP AT i_tab2 ASSIGNING FIELD-SYMBOL(<pattern2>.
FIND <pattern2> IN i_text MATCH OFFSET DATA(moff2)
MATCH LENGTH DATA(mlen2).
...
ENDLOOP.
ENDIF.

ENDMETHOD.

Including Structures

5.1.5.1 Background

In the program-internal design of structures with the BEGIN OF and END OF additions of the TYPES and DATA
statements, you can use the INCLUDE TYPE or INCLUDE STRUCTURE statements to integrate all
components of another structure with the current structure at this place without creating a specific substructure.
You can specify a name for shared addressing and a suffix to avoid naming conflicts. The ABAP Dictionary
provides the same functionality.
Substructures, in contrast, are formed if the components of a structure themselves are structured. A structure
with substructures is known as a nested structure.

5.1.5.2 Rule

Page: 137 of 227


Do not include components from structures

Do not integrate the components of other structures by using INCLUDE when declaring a structure. If required,
you can include the components in a real substructure.

5.1.5.3 Details

The reasons for this rule are the following:

• The integration of components can lead to naming conflicts. This is particularly problematic if structures
of other contexts are integrated and changed retroactively.

• Although it is possible to assign a name, the integrated structures cannot be addressed as such without
restrictions. The necessary internal type information is individually stored for each integrated
component. For the components of a substructure, however, this information is stored only once for the
substructure

• In contrast to real substructures, structures integrated using INCLUDE cannot be declared as boxed
components. A boxed component is a structured component, which is managed through an internal
reference and thus supports initial value sharing. This can considerably reduce the memory
requirements for rarely filled components.

• The statement cancels a chained statement that has been created with BEGIN OF and END OF.

If no real substructures can be formed, you must avoid naming conflicts as far as possible by using suffixes
(RENAMING WITH SUFFIX addition). This recommendation also applies to the integration of structures in the
ABAP Dictionary, where you cannot always create real substructures (for example, for database tables).

5.1.5.3.1 Bad example

The following source code shows the integration of the components of a structure into another structure, which
is not recommended according to the above rule.

TYPES:
BEGIN OF structure_1,
...
END OF structure_1.
TYPES:
BEGIN OF structure_2,
...
INCLUDE TYPE structure_1 AS sub_structure.
TYPES:
...
END OF structure_2.

5.1.5.3.2 Good example

The following source code shows the declaration of a component of a structure as a substructure as
recommended in the above rule.
TYPES:
BEGIN OF structure_1,
...
END OF structure_1.
TYPES:
BEGIN OF structure_2,

Page: 138 of 227


... sub_structure TYPE
structure_1.
...
END OF structure_2.

Using Types

5.1.6.1 Background

You can use the data types declared according to the rules on Bound and Standalone Data Types and
Declaration of Data Types and Constants for declaring and generating data objects, as well as for typing field
symbols or interface parameters. You specify them after the TYPE addition of the corresponding statement.

5.1.6.2 Rule

Use semantically appropriate data types only

Use existing types only if they match the semantics of the typed object. You must not select an existing type
based only on the technical properties.

5.1.6.3 Details

As long as it extends beyond an elemental ABAP type, the type of a data object or an interface parameter
provides the source code reader with information on the semantics of these variables. This makes it easier to
recognize the meaning of individual variables.

For this reason, you must use only data types whose semantics match the usage. The technical properties of a
type alone do not justify its use in a specific context, as this impedes the readability of the program.

In particular, this applies to the reuse or multiple use of existing types. If you require a data type with specific
technical properties for an application, you should not simply use any type with these properties from the ABAP
Dictionary. In the past, this has frequently been the chosen procedure. Consequently applying package
encapsulation may help prevent the unwanted use of own data types.

5.1.6.3.1 Note

This rule applies especially for the use of structures from the ABAP Dictionary. For example, you should never
use a structure defining a database table as a template for input or output fields of classical dynpros or in Web
Dynpro. This would violate the SoC principle.

5.1.6.3.2 Bad example

In the following source code a variable is declared, whose name and use clearly indicate that it is used for a
truth value. The variable is declared with a technically correct, but semantically incorrect, data type. syst-batch,
after all, is the data type for the system field sy-batch, which indicates whether a program is executed in the
background.
DATA is_empty TYPE syst-batch.
...
IF is_empty IS INITIAL.
...
ENDIF.

5.1.6.3.3 Good example

Page: 139 of 227


The following source code shows an improved example compared to the source code above. In this case, the
abap_bool type of type group abap, which is intended for truth values, is used. In addition, the request of the
truth value is performed using a specifically designated constant from the same type group.

DATA is_empty TYPE abap_bool.


...
IF is_empty EQ abap_false.
...
ENDIF.

Reference to Data Types or Data Objects

5.1.7.1 Background

As well as using data types for declarations and typings with the addition TYPE, you can use the alternative
addition LIKE of the corresponding statements to directly reference the data type of one of the data objects
visible at this position. This includes references to data objects of the same program, interface parameters of
the current procedure, attributes of global classes and interfaces, and constants in type groups.

5.1.7.2 Rule

Declare dependent data objects with reference to other data objects

If a data object directly depends on another data object, refer to it directly using LIKE for the declaration. In all
other cases, use TYPE to refer to a standalone data type.

5.1.7.3 Details

For example, if a helper variable of the type of an input parameter is required within a procedure (method), you
should not declare it with reference to the type of the parameter using TYPE but with reference to the
parameter itself using LIKE. You can also declare work areas using LIKE LINE OF if the parameter is an
internal table. In the case of typing with LIKE, you can retroactively change the type of the parameter without
always having to adapt the procedure implementation.

However, if no close reference to another data object exists, it is usually more useful to declare data objects
with reference to a standalone data type by using TYPE.

5.1.7.4 Note

You should never implement an obsolete reference to flat structures or database tables or views of the ABAP
Dictionary with LIKE.

5.1.7.4.1 Bad example

The following source code shows the declaration of a helper variable in a method that is supposed to be of the
same data type as an interface parameter. The TYPE reference to the data type requires a manual
implementation of any type changes.

CLASS some_class DEFINITION ...


PUBLIC SECTION.
METHODS some_method
CHANGING some_parameter TYPE some_type.
...

Page: 140 of 227


ENDCLASS.
CLASS some_class IMPLEMENTATION.
METHOD some_method.
DATA save_parameter TYPE some_type.
save_parameter = some_parameter.
...
ENDMETHOD.
...
ENDCLASS.

5.1.7.4.2 Good example

The following source code shows the improved declaration of the helper variable that now directly refers to the
interface parameter with LIKE, so that possible type changes are automatically accepted.

...
METHOD some_method.
DATA save_parameter LIKE some_parameter.
save_parameter = some_parameter.
...
ENDMETHOD.
...

Table Work Areas

5.1.8.1 Background

Table work areas are structured data objects of a flat structure type, a database table type, or a view type from
ABAP Dictionary declared using the statements TABLES or NODES. If declared using NODES, then other
ABAP Dictionary types are also possible.

From the perspective of the data type, the statements

TABLES table_wa.
NODES table_wa.

are the same as

DATA table_wa TYPE table_wa.

This means that data objects with the same name and type as the corresponding data types from ABAP
Dictionary are declared. This is supplemented by further meanings of TABLES and NODES. For the full range
of meanings, refer to the ABAP Keyword Documentation. The essential properties are as follows:

• TABLES and NODES declare interface work areas, which are shared by multiple programs of a
program group.
• TABLES declares interfaces to classic dynpros and selection screens.

• NODES declares an interface to logical databases.

In addition, it is also possible to use table work areasdeclared using TABLES as implicit work areas in obsolete
abbreviated forms of Open SQL, or even older statements for database accesses.

5.1.8.2 Rule

Page: 141 of 227


No table work areas except for classic dynpros

Only use the statement TABLES in the global declaration part of function groups to communicate with classic
dynpros. Apart from in wrappers of logical databases, the statement NODES is no longer required.

5.1.8.3 Details

The statement TABLES is not allowed within classes anyway and the statement NODES can only be created
syntactically in the global declaration part of an executable program associated with a logical database. The
latter option is no longer allowed.

Since obsolete database accesses requiring the statement TABLES and shared data areas between programs
are not allowed, there is no need to use the statement TABLES, except for declaring interfaces to classic
dynpros (see the following exception).

5.1.8.3.1 Exception

If dynpro fields in classic dynpros are defined with reference to flat structures in ABAP Dictionary, the
homonymous global data objects of the ABAP program must be declared with the statement TABLES.
Otherwise, the data objects of the ABAP program are not linked to the dynpro fields, and their content cannot be
accessed. In addition, TABLES is also required for declaring specific work areas when handling function codes
of selection screens.

5.1.8.3.2 Note

The restriction on the statement TABLES to this last remaining technical requirement, that is, the
communication with classic dynpros and selection screens, can also be derived from other rules of these
guidelines. However, since the use of the statement TABLES instead of the statement DATA is still very popular
among experienced ABAP developers, the above-mentioned rule explicitly stresses its prohibition.

Literals

5.1.9.1 Background

A literal is a data object defined in the source code of a program by specifying a character-like value. Possible
literals are:

• Numeric literals
Sequence of digits with an optional plus/minus sign. The data type is either i or p.

• Character literals o Text field literals, which are enclosed in single speech marks ('). The data

type is c.

o String literals, which are enclosed in back quotes (`). The data type is string.

In numeric literals, neither decimal separators nor scientific notation with mantissa and exponent are possible.
Character literals with correct content must be used to represent thesetypes of numeric values.

5.1.9.2 Rule

Page: 142 of 227


Avoid using literals in operand positions

Avoid using literals to specify values directly in the source code. Instead constants should be declared with
these values. This applies to numerical values in particular.

5.1.9.3 Details

Certain values are required in more than one place in the source code. It is therefore not helpful to specify these
values directly in the source code, since several statements would need to be modified each time the value is
changed. An appropriate constant can be used instead to enable the value to modified at a central position in
the source code. Literals are, of course, allowed when specifying values in the declaration of the constants.
This can make the program significantly easier to maintain and enhance at a later date.

It can also be a good idea to create an appropriate constant for values used in only one place. The name of the
constant gives the values semantics that make the source code easier to understand.

Number literals that appear in source code seemingly without any semantic meaning are often known as "magic
numbers". Avoid using these in ABAP programs. When using character literals, translatability is also important.

5.1.9.3.1 Exception

In certain situations, however, using constants can affect the readability of a program. It is better to specify a
literal in these cases, as in the following examples:

• CALL FUNCTION 'MY_FUNC'.

• IF sy-subrc = 0.

• READ TABLE itab INDEX 1 or itab[ 1 ]

• ADD 1 TO counter.

These examples make the semantic meaning of the literals clear and translatability is not an issue.

Another area where character literals are vital is dynamic programming. Here, parts of statements or entire
programs are generated, which is virtually impossible without using character literals. In addition, string
templates offer various enhanced options for using literal texts.

5.1.9.3.2 Bad example

The following source code uses the same literal multiple times to specify pi (π) in operand positions. This
multiple use makes the program unclear and error-prone.

DATA: radius TYPE decfloat34,


circumference TYPE decfloat34,
area TYPE decfloat34.
...
circumference =
2* '3.141592653589793238462643383279503' * radius.
area =
'3.141592653589793238462643383279503' * radius ** 2.

5.1.9.3.3 Good example

Page: 143 of 227


The following source code declares a constant that requires the literal with the value pi (π) only once, and uses
it in the appropriate operand positions.

CONSTANTS pi TYPE decfloat34


VALUE '3.141592653589793238462643383279503'.
DATA: radius TYPE decfloat34,
circumference TYPE decfloat34,
area TYPE decfloat34.
... circumference = 2 * pi *
radius. area = pi *
radius ** 2.

Strings

5.1.10.1 Background

Strings are dynamic data objects of variable length. There are text strings of the string data type and byte
strings of the xstring data type, in which you can store character or byte strings.

In contrast to text and byte fields of a fixed length (c, x data types), the length of strings automatically adapts to
the content. Other data types, such as n, d, and t, are also treated as text fields in many operand positions.
Strings are deep data objects that are internally managed by references. For this, the following additional
memory is required:

• Strings whose length is less than approximately 30 characters or 60 bytes require between
approximately 10 and 40 bytes of additional memory, depending on the string length.

• For longer strings, the additional memory requirement is approximately 50 bytes, irrespective of the
string length.

In the case of assignments between strings, sharing takes effect. This means that only the internal reference is
copied first. Sharing is canceled if the source or target object is accessed for modification.

5.1.10.2 Rule

Use Strings for Character and Byte String Processing

Use strings rather than fixed length fields for the internal storage and processing of character and byte strings.

5.1.10.3 Details

Strings are more flexible than fields of a fixed length and usually help you save memory space, because no
unnecessary space is occupied by blanks or zeros, and because sharing is implemented for assignments.
Furthermore, closing blanks are always significant in text strings. Text fields simply ignore closing blanks in
many operand positions (but not in all), which may be quite confusing at times.

5.1.10.3.1 Exception

In the following cases, fields of a fixed length should be used instead of strings:

• The length of the field is critical, for example, for templates or for interfaces to screen fields.

Page: 144 of 227


• Despite sharing, the additional administration work outweighs the benefits which can often be the case
for very short strings. If it is obvious that a certain length is never exceeded, you can also use short
fields of a fixed length.

• Structures that only contain character-type components are supposed to be treated like a single text
field. This is not possible for structures that contain text strings.

5.1.10.3.2 Bad example

The following source code shows an internal table for storing an HTML page whose line type is a text field with
a fixed length of 255.

TYPES html_line TYPE c LENGTH 255.


DATA html_table TYPE TABLE OF html_line.
APPEND '<HTML>' TO html_table.
...
APPEND '<BODY>' TO html_table.
...
APPEND '</BODY>' TO html_table.
APPEND '</HTML>' TO html_table.

5.1.10.3.3 Good example

The following source code shows the above example but uses text strings. The memory space gained should
outweigh the additional administration effort considerably. As an alternative to using an internal table, you can
also concatenate the HTML page in a single text string; however, this impairs the legibility, for example, in the
ABAP Debugger.

DATA html_table TYPE TABLE OF string.


APPEND `<HTML>` TO html_table.
...
APPEND `<BODY>` TO html_table.
...
APPEND `</BODY>` TO html_table.
APPEND `</HTML>` TO html_table.

Start Values

5.1.11.1 Background

If you declare a data object with the DATA statement, you can use the VALUE addition to set a value, with which
the data object is filled when it is created. If the VALUE addition is not used, the system uses the type-specific
initial value. If the CONSTANTS statement is used, the VALUE addition must always be specified. If the
typecompliant initial value is required here, this can be achieved using the addition VALUE IS INITIAL.

If the specified start value does match the type and length of the data object, the value is converted when the
program is generated.
5.1.11.2 Rule

Start values must match the data type of the data object

Only use the addition VALUE to enter start values that exactly match the data type of the declared data object in
terms of type, content, and length.

Page: 145 of 227


5.1.11.3 Details

The start value cannot always be specified to conform with the type, since ABAP does not support
typecompliant literals for all possible data types. In all cases where a conversion cannot be avoided, choose the
content of literals specified as start values so that the actual value meets the requirements when the source
code is read.

5.1.11.3.1 Bad example

The average reader may well expect the constant high_noon in the following source code to contain the value
120000. However, the constant actually contains the value 092000, because the value of the numerical literal
refers to the number of seconds. This means 12,000 seconds is actually the time 09:20 on the following day.

CONSTANTS high_noon TYPE t VALUE 120000.

5.1.11.3.2 Good example

The following source code corrects the above example by replacing the number literal with a text field literal.
Now the constant high_noon contains the expected value 120000.

CONSTANTS high_noon TYPE t VALUE '120000'.

Data Objects for Truth Values

5.1.12.1 Background

Logic values are results of logical expressions. A logic value is either true or false. ABAP does not yet support
boolean data types and thus does not support data objects for logic values. Therefore, the result of a logical
expression cannot be assigned directly to a data object.

It has become common practice to express the logic value "true" as value "X" and the logic value "false" as a
blank (" "). There are also boolean functions that have a logical expression as an argument and are returned as
the value "X" or a blank, depending on the result.

To make it easier to handle logic values expressed in this way, the type group abap contains a data type
abap_bool of elementary type c with length 1, and the constants abap_true of value "X" and abap_false of value
" " as substitutes for a real boolean data type. There is also a constant abap_undefined of value "-".

5.1.12.2 Rule

Using the Data Type abap_bool for Logic Values

When working explicitly with logic values, use the type abap_bool as a substitute for a real boolean data type. A
data object declared in this way should have no values other than the relevant constants abap_true and
abap_false (also abap_undefined).
5.1.12.3 Details

Using the type abap_bool and the constants abap_true and abap_false makes it clear that logic values are
being used here.

In accordance with the rule for avoiding literals in operand positions, not only the literals 'X' and ' ' should be
used. State queries about the predicate operators IS INITIAL and IS NOT INITIAL or the use of the constant
space are also not advisable, because they require knowledge of the technical values of abap_true and
abap_false, which are not significant in the sense of real boolean data objects.

Page: 146 of 227


The type group abap contains a third constant for the type abap_bool, namely abap_undefined. However,
implementing a three-value logic is only useful and recommended in exceptional cases. In this case, note that
abap_undefined does not contain the initial value for a variable of type abap_bool. The initial value is always
the value of abap_false. However, the value of abap_undefined can, if required, be specified using the addition
VALUE when declaring a logic value as the start value.

5.1.12.3.1 Bad example

The following source code shows an unsuitable emulation of the boolean data objects not present in ABAP.

DATA is_found TYPE c LENGTH 1.


... is_found =
'X'.
...
IF is_found IS NOT INITIAL.
...
ENDIF.

5.1.12.3.2 Good example

The following source code shows the recommended emulation of the boolean data objects not present in ABAP.

DATA is_found TYPE abap_bool.


... is_found =
abap_true.
...
IF is_found = abap_true.
...
ENDIF.

5.2 Assignments, Calculations and Other Types of Data Access


An assignment passes the content of a data object, a return value, or a result of a calculation expression to a
data object. If the data types are compatible, the content is copied unchanged. If the data types are
incompatible and there is a suitable conversion rule, the content is converted. An assignment is usually
performed with the assignment operator (=).

A calculation is executed in a calculation expression, which can be specified in an operand position, in particular
on the right side of the assignment operator =. If necessary, the result of a calculation expression is converted
to the data type of the operand position or of the result of the assignment. In arithmetic expressions, the
calculation is executed in a calculation type based on the data types of all operands including the result.
Assignments Between Different Types

5.2.1.1 Background

ABAP allows a direct assignment between data objects with different data types. There must be a suitable
conversion rule and the content of the source field must be a meaningful value for the data type of the target
field. If a suitable conversion rule is not found or the content of the source field is not suitable, an exception
occurs.

Such conversions take place not only in direct assignments, but also in many operand positions and in
particular in arithmetic calculations, if the specified operand does not have the data type expected at the
position.

Page: 147 of 227


5.2.1.2 Rule

Avoiding Conversions

Where possible, assignments should be performed between compatible data objects with the same data type.

5.2.1.3 Details

Type conversions incur additional runtime and may not always have the result intended by the developer.
Therefore, conversions should only be performed between data objects with different data types if there is no
other choice. In particular, conversions should be avoided where the conversion rules produce unexpected
results.

5.2.1.3.1 Bad example

The following source code shows an arithmetic calculation involving two unnecessary conversions. First the text
field literal '1' has to be converted to the calculation type i, then the result of the calculation has to be converted
from type i to data type n. Such conversions produce significant increases in runtime.

DATA index TYPE n LENGTH 4.


...
DO ... TIMES.
index = sy-index - '1'.
...
ENDDO.

5.2.1.3.2 Good example

The following source code hows how code can be improved compared to the previous example, so that no
conversions are necessary.

DATA index TYPE i.


...
DO ... TIMES.
index = sy-index - 1.
...
ENDDO.

Avoiding Invalid Values

5.2.2.1 Background

For performance reasons, the ABAP runtime environment does not check whether the target field contains a
valid value after each and every assignment. Particularly for target fields of character-like data types n, d, and t,
the conversion rules allow any alphanumeric values as the result of an assignment. However, only the following
values are valid:

• For type n: numbers only

• For type d: a calendar date in the format "YYYYMMDD"

• For type t: a time in the format "HHMMSS"

Page: 148 of 227


For a detailed description of the validity of character-like date and time fields, see also the relevant section of
the documentation.

A lossless assignment can be used to force checks on valid values.

5.2.2.2 Rule

Only assign valid values

In assignments and calculations, data objects are filled with data types n, d, and t with valid values only.

5.2.2.3 Details

Statements that work with variables with types n, d, or t can only be guaranteed to behave correctly if values
are valid. If character-like date and time fields are required, it is important to be be aware of their special
characteristics. Since the initial value for variables of type d is itself not a valid value, a suitable start value must
always be specified by using the addition VALUE. Note that in arithmetic calculations with character-like date
fields, if an assignment to a target field with data type d has 0 as a result value, this is an invalid initial value and
may require special treatment.

If the responsibility for filling data objects of the critical data types lies elsewhere, it is best to always check the
validity of their content before use. Lossless assignments with the operator EXACT can be used to do this. Note
that the initial value of a character-like date field of type d is interpreted as valid for a lossless assignment, and
the value "00010101" as invalid.

5.2.2.3.1 Bad example

The following source code shows a case where the conversion rules in ABAP can lead to problems if not used
properly in combination with character-like date fields. The literals can be passed to the character-like date
fields, without raising an exception, to give the values 07092009 and 16092009. Unfortunately, these are
interpreted as 09.20.0709 and 09.20.1609, which are invalid dates. During the calculation, they are both
converted to the value 0 and the result is 0. Looking at the dates, the expected result would be 9.

DATA: date1 TYPE d,


date2 TYPE d,
result TYPE i. date1
= '07092009'. date2 =
'16092009'. result =
date2 - date1.
5.2.2.3.2 Good example

The following source code shows a date calculation that does give the expected result of 9, thanks to valid
values in the date fields. The validity of the literal values is guaranteed by using the appropriate typed literals.

DATA: date1 TYPE d,


date2 TYPE d,
result TYPE i. date1
= d`20090907`. date2
= d`20090916`.
result = date2 - date1.

The following source code shows how to check whether the character-like date fields are valid in the
calculation, if they are not filled in the same program. Since the EXACT operator does not perform a check for
compatible types, the data fields are first converted to temporary text strings, and these are checked.

Page: 149 of 227


TRY.
result = EXACT d( CONV string( date2 ) ) -
EXACT d( CONV string( date1 ) ).
CATCH cx_sy_conversion_no_date.
...
ENDTRY.

Using Conversion Rules

5.2.3.1 Background

ABAP contains numerous conversion rules for assignments between data objects of different data types. These
rules relate to assignments between:

• Elementary data objects

• Elementary data objects and structures

• Structures

• Internal tables

• Reference variables

Assignments between data objects of nearly every different data type are possible. The only prohibited
assignments are for data types for data and time specifications. Almost all permitted assignments have a
corresponding conversion rule. It is especially important to have rules for assignments between data objects of
the same data type, if different technical properties (such as length or number of decimal places) are allowed.
Lossless assignments permit only conversions that produce valid values and where no values are lost.

5.2.3.2 Rule

Avoid unexpected conversion results

Only assign data objects to each other if the content corresponds to the data type of the target field and
produces an expected result. Do not exploit every ABAP conversion rule to its full extent. Consider using
lossless assignments.
5.2.3.3 Details

The ABAP conversion rules are based on the philosophy that assignments should be allowed between as many
combinations of values as possible, without generating exceptions. In this situation, ABAP behaves quite
differently from other programming languages. In other languages, assignments between different data types
are usually handled much more strictly and special conversion routines or explicit casting for specific requested
conversions are used.

Although it is convenient to be able to readily assign all possible data objects to each other, there are also
disadvantages, such as the generation of invalid values. Another example is implicit casting, which occurs when
assignments are made between elementary data objects and structures, or between incompatible structures.

Even if no invalid values are generated, problems still can occur. If valid target values are generated from
invalid source values, this does not necessarily meet the expectations of the reader and it can make program
maintenance considerably difficult. One example of this is the handling of invalid content in the source field in

Page: 150 of 227


assignments from a character-like type to a byte-like type. Instead of exiting the assignment with an exception,
hexadecimal zeros are passed from the first invalid character.

The only solution here are lossless assignments with the operator EXACT, which produce an exception in these
cases. Even though this is a bit late in the day, the behavior of an assignment with the operator EXACT could
be regarded as the normal, expected behavior. Other unexpected behaviors represent an implementation of
special rules, which is actually the standard behavior in ABAP.

5.2.3.3.1 Bad example

Anyone who is familiar with all the details of the ABAP conversion rules would probably expect an exception
when the text in the following source code is assigned to the numeric text. However, only the digits of the text
are respected. Therefore, the target field is given the value "00000043" instead of the value "00000007", which
might also be expected.

DATA text TYPE string, num_text


TYPE n LENGTH 8.
... text = '4 Apples + 3
Oranges'.
... num_text =
text.

5.2.3.3.2 Good example

This issue is corrected in the source code below. The EXACT operator is used, which triggers an exception.

... text = '4 Apples + 3


Oranges'.
...
TRY.
num_text = EXACT #( text ).
CATCH cx_sy_conversion_error.
...
ENDTRY.

Trailing Blanks in Character Literals

5.2.4.1 Background

Trailing blanks in text field literals use memory, but are generally ignored in operand positions, like all data
objects of the type c. In text string literals they are always relevant, as in all data objects of type string.
5.2.4.2 Rule

Do not use trailing blanks in text field literals

They should also not be specified in literals in any operand positions where trailing blanks are not relevant.

5.2.4.3 Details

This rule is designed mainly to make programs more readable. It makes no sense to specify literal characters in
positions where they are ignored, and raises expectations in users of the program that cannot be met. In
particular, this also applies for the text field literal ' '.

Page: 151 of 227


Conversely, the specification of the supposedly empty text field literal '' in positions where closing spaces are
taken into account may be a trap.

5.2.4.3.1 Bad example

The following simple example demonstrates the full scope of the rule. Any readers with little experience in ABAP
would expect the result of the assignment to be a string with length six. In actual fact, the result contains only
the three relevant positions.

DATA text TYPE string.

text = '123'.

5.2.4.3.2 Good example

Whether the example needs to be improved depends on whether the trailing blanks are required. If the blanks
are needed, use a string literal:

text = `123 `.

If they are not needed, leave them out:

text = '123'.

5.2.4.3.3 Bad example

The following example demonstrates that the supposedly empty literal '' actually represents a blank that is not
cut off after SEPARATED BY. The result is "AB AP".

DATA text TYPE string.

CONCATENATE 'AB' 'AP' INTO text SEPARATED BY ''.

5.2.4.3.4 Good example

Depending on whether the blank is needed as a separator, either ' ' or `` must be specified after SEPARATED
BY to express this clearly.

Specifying Numbers

5.2.5.1 Background

There are no special literals available for numbers with decimal places, or with mantissa plus exponent. If
required, these numbers must be expressed using character literals. The following notations can be used:

• Mathematical notation
A sequence of digits with a maximum of one period (.) as a decimal separator and an optional
sign "+" or "-" on the left. This sign can be separated from the digits by blanks, for example: - 1234.56

• Commercial notation
A sequence of digits with a maximum of one period (.) as a decimal separator and an optional
sign "+" or "-" on the right. This sign can be separated from the digits by blanks, for example: 1234.56-

Page: 152 of 227


• Scientific notation
A sequence consisting of a mantissa (an optional sign "+" or "-", digits with a maximum of one
period (.) as a decimal separator), a character e or E, and an exponent (an optional sign "+" or "-" and
further digits), for example: -1.23456E03

5.2.5.2 Rule

Use globally valid notation for numeric values

When using numbers in character strings that are intended for assignments to a numeric data object, create
them so that they are accepted by all possible target types. The sign must always be on the left, and there must
be no blanks.

5.2.5.3 Details

When converting a character string to a numeric variable, the type of the target variables decides which
notations are accepted:

• If the type of the target variable is decfloat16 or decfloat34, all three notations are accepted.

• If the type of the target variable is f, all three notations are accepted. The mathematic and commercial
notations are only accepted, however, if the sign is not separated from the digits by one or more blanks
and there are blanks in front of the digits.

• If the type of the target variable is p or i, only the mathematic and commerical notations are accepted.

To make sure that a program is readable, and also that numbers in character strings can be converted to as
many numeric data types as possible, always use mathematical notation without blanks between the sign and
the digits. This notation also confirms to other standards, such as the canonic representation of XML schema
data types.

5.2.5.3.1 Bad example

The following source code demonstrates the initialization of a generically typed parameter with commercial
notation, where the sign is separated by a blank. If an actual parameter with a type other than f is passed, the
assignment produces the value -1000 (as expected); if an actual parameter of the type f is passed, however,
the value is +1000.
CLASS class DEFINITION.
PUBLIC SECTION.
METHODS calculate_something
EXPORTING number TYPE numeric.
ENDCLASS.
CLASS class IMPLEMENTATION.
METHOD calculate_something.
number = '1000 -'.
...
ENDMETHOD.
ENDCLASS.

5.2.5.3.2 Good example

The following source code demonstrates an assignment using globally valid notation that is easy to read and
which produces the same result, the value -1000, for all numeric data types.

Page: 153 of 227


METHOD calculate_something.
number = '-1000'.
...
ENDMETHOD.

Selecting the Numeric Type

5.2.6.1 Background

Several numeric types with various properties and value ranges are available in ABAP, which you can use for
storing numbers and for calculations:

• Signed 4-byte and 8-byte integers (type i). There are also 1-byte and 2-byte integers with the internal
types b and s. However, these data objects cannot be generated based on a predefined ABAP type.
Instead, the predefined ABAP Dictionary types INT1 and INT2 are required.

• Packed numbers in BCD format (binary coded decimals, type p)

• Binary floating point numbers (type f)

• Decimal floating point numbers (types decfloat16, decfloat34)

The decimal floating point numbers meet the requirements for highly exact processing of decimal numbers in a
large value ranges, where the data types p and f only cover a single aspect each.

5.2.6.2 Rule

Select suitable numeric types for numbers and calculations

Select a numeric type to suit the values that you want to map, in order to achieve the highest possible speed
and accuracy. Here is a general rule of thumb:

• i

• p for fixed point numbers


• decfloat16 or decfloat34 for floating point numbers

• f in exceptional cases only

5.2.6.3 Details

The calculation speed and accuracy are generally contradictory requirements and depend on the data type of
the objects to be processed. Therefore, when selecting the numeric type, you must weigh up these two
requirements. These considerations must also include the value range to be mapped:

• If the values to be mapped are integers, type i must usually be used. This guarantees the highest
possible calculation speed. Examples of these integers include counters, indexes, offsets and time
intervals. If the values to be mapped exceed the value range of type i, you can use type p without
decimal places instead. The calculation speed is slower, but decimal places are still mapped accurately
(except for rounding errors). If this value range is still not sufficient, you can use a floating point type
(decfloat16 and decfloat34) instead.

Page: 154 of 227


• If you have to map nonintegral values that have a fixed number of decimal places, you can use type p.
However, calculations with type p are executed in the ABAP kernel and not by the hardware. Examples
of non-integral values include lengths, weights, or monetary amounts. If this value range is still not
sufficient, you can use a decimal floating point type (decfloat16 and decfloat34) instead. The binary
floating point type f is less suitable because it cannot map all decimal fractions. This is a further
impediment for calculation accuracy (in addition to the unavoidable rounding errors).

• For nonintegral values with a variable number of decimal places or a large value range, you should use
the decimal floating point types decfloat16 or decfloat34. Decfloat34 has a larger number of decimal
places and a larger value range. However, this also leads to increased memory consumption.

Thanks to the hardware support available on all platforms, binary floating point type f allows fast calculations.
However, it is inferior to the new decimal floating point types due to the following reasons:

• Type f can only accuately map fractions with the power of two in the denominator (1/2, 1/4, 1/8, etc.)
and totals. Other values are rounded according to this mapping. This rounding process does not
correspond to the decimal rounding process (and usually does not meet the expectations of the
developer or user). For example, the value 0.815 is approximated internally as 8.1499999999999995E-
01. This means when the value is rounded to two decimal places, 0.81 is returned instead of the
expected value 0.82.

• Yery large numbers can no longer be exactly mapped (working in line with IEEE 754), if the difference
between the largest and smallest exponent is larger than 52 (in the total of powers of two). For
example, 1E+23 is mapped as 9.9999999999999992E+22.s

• A number of type f cannot be rounded to a specific number of decimal places, if the result needs to be
assigned to another number of type f.

• Divisions by powers of 10, which often occur when converting metric units, for example, are not exact.
8.0500000000000005E-01 is returned for 805/1000, for example.

• Simple calculations often produce unexpected results. 123456.15 - 123455 returns


1,1499999999941792, for example.

• The conversion of binary floating point numbers to other number formats is not clearly defined in line
with IEEE 754. Consequently, when data is stored in the database, the rounding behavior depends on
the platform and how numbers of type f are mapped in the database.
• The decimal floating point types decfloat16 and decfloat34 do not have these problems. Both have a
larger value range than type f, and decfloat34 has 34 decimal places instead of 16 decimal places.
However, the following restrictions apply:

o Currently, calculations with decimal floating point types are generally even slower than calculations
with the type f (the speed is comparable to calculations with the type p). Until now, only IBM's
Power6 architecture provided hardware support for floating point calcuations of this type in
accordance with IEEE-754-2008. On other platforms, calculations with decimal floating point
numbers have to be performed on the software side in the ABAP kernel, in a similar way to
calculations with the type p.

o Decimal floating point types are not yet supported by associated data types on all database
platforms. As an interim solution, ABAP Dictionary provides a set of predefined data types
DF16_..., DF34_..., based on existing types (DEC and RAW). In most cases, the benefits of the
decimal floating point types compensate for the current slow calculation speed. However, you might
still need to use type f, if you have stringent requirements for performance and less stringent
requirements for calculation accuracy. Remember that the speed advantage currently possible for

Page: 155 of 227


calculations with f, may be outweighed by the fact that conversions from f to other numeric types
are relatively slow.

5.2.6.3.1 Note

For programs that are currently created with decimal floating point types, the performance is increased as soon
as the processor architecture supports decimal floating point calculations and the ABAP runtime environment
starts using this hardware support. Calculations with decimal floating point numbers then become faster than
calculations with packed numbers.

5.2.6.3.2 Bad example

The following source code shows a declaration of a binary floating point number. The start value 0.815 is
assigned. The true start value, however, is 8.1499999999999995E-01.

DATA number TYPE f VALUE '0.815'.

5.2.6.3.3 Good example

The following source code shows a declaration of a decimal floating point number. The start value 0.815 is
assigned. The true start value is actually 8.15E-01.

DATA number TYPE decfloat34 VALUE '0.815'

Rounding Errors

5.2.7.1 Background

In the case of assignments between floating point numbers (types f, decfloat16, decfloat34) and fixed point
numbers (types i and p), rounding errors usually occur that produce an incorrect value. However, values of type
p (and also decfloat16,decfloat34) assigned to type f are not always displayed accurately.

5.2.7.2 Rule

Avoid unnecessary rounding errors


Avoid unnecessary or frequent conversions between floating point numbers and fixed numbers as this can
cause rounding errors.

5.2.7.3 Details

In a program, the value of a number should always be stored for as long as possible in a data object with the
numerical data type of the highest required level of accuracy. This applies especially to saving intermediate
results of calculations.

The data input or output requirements (for example, formatting on the screen or in a spool list) cannot change
the way numbers are saved internally. If a number is to be formatted using a specific number of decimal places,
the actual value should not be converted to the corresponding packed number. Instead, a suitable format
should be configured in a character-like field using the relevant constructs. These are character string templates
and previously the statement WRITE TO.

5.2.7.3.1 Bad example

Page: 156 of 227


The following source code shows a calculation where results can be assigned to a numerical field intended for
output. The result 55.55 is rounded to 56.00.

DATA: output TYPE p DECIMALS 2,


percentage TYPE decfloat34,
value TYPE decfloat34. percentage =
'55.55'. value = '100.0'.
output = percentage / 100.
output = value * output.

5.2.7.3.2 Good example

The following source code corrects the above example by separating the code into data objects intended for
calculations and a character-like data object for the formatted output.

DATA: result TYPE decfloat34,


percentage TYPE decfloat34,
value TYPE decfloat34.
DATA output TYPE c LENGTH 40.
percentage = '55.55'.
value = '100.0'.
result = percentage / 100.
result = value * result.
WRITE result TO output DECIMALS 2 EXPONENT 0.

Dividing by Zero

5.2.8.1 Background

In the case of assignments between floating point numbers (types f, decfloat16, decfloat34) and fixed point
numbers (types i and p), rounding errors usually occur that produce an incorrect value. However, values of type
p (and also decfloat16,decfloat34) assigned to type f are not always displayed accurately.

5.2.8.2 Rule

Avoid unnecessary rounding errors


Avoid unnecessary or frequent conversions between floating point numbers and fixed numbers as this can
cause rounding errors.

5.2.8.3 Details

In a program, the value of a number should always be stored for as long as possible in a data object with the
numerical data type of the highest required level of accuracy. This applies especially to saving intermediate
results of calculations.

The data input or output requirements (for example, formatting on the screen or in a spool list) cannot change
the way numbers are saved internally. If a number is to be formatted using a specific number of decimal places,
the actual value should not be converted to the corresponding packed number. Instead, a suitable format
should be configured in a character-like field using the relevant constructs. These are character string templates
and previously the statement WRITE TO.

5.2.8.3.1 Bad example

Page: 157 of 227


The following source code shows a calculation where results can be assigned to a numerical field intended for
output. The result 55.55 is rounded to 56.00.

DATA: output TYPE p DECIMALS 2,


percentage TYPE decfloat34,
value TYPE decfloat34. percentage =
'55.55'. value = '100.0'.
output = percentage / 100.
output = value * output.

5.2.8.3.2 Good example

The following source code corrects the above example by separating the code into data objects intended for
calculations and a character-like data object for the formatted output.

DATA: result TYPE decfloat34,


percentage TYPE decfloat34,
value TYPE decfloat34.
DATA output TYPE c LENGTH 40.
percentage = '55.55'.
value = '100.0'.
result = percentage / 100.
result = value * result.
WRITE result TO output DECIMALS 2 EXPONENT 0.

Casting

5.2.9.1 Background

Casting refers to the process of handling a data object by assuming a certain data type. This definition is
different to the meaning of the concept in other programming languages, such as Java. Here, casting means a
different concept which is referred to as 'conversion' in ABAP. Casting in ABAP is either explicit or implicit:

• Explicit casting is possible by using the CASTING addition with the ASSIGN statement and by using the
ASSIGNING addition in statements for processing internal tables. Assignments between reference
variables allow up casts and down casts. Obsolete explicit casting is also possible for formal
parameters and field symbols, if the STRUCTURE addition is used.
• Implicit casting is sometimes performed for special assignments or during operand handling at certain
operand positions. A common example is the handling of flat structures with only character-like
components as a single field of type c. In obsolete non-Unicode programs, this even applies to any
type of flat structure.

5.2.9.2 Rule

Avoid implicit casting

Avoid implicit casting. If a cast to another data type is required, it can usually be implemented explicitly using
ASSIGN ... CASTING.

5.2.9.3 Details

Implicit casting can potentially occur if structures are used as follows:

Page: 158 of 227


• Assignments between incompatible structures or structures and elementary data objects

• Comparisons between structures and elementary data objects

• Using structures in operand positions where elementary data objects are expected

• Reads from the database using SELECT * ... INTO wa

• Using the INCREMENT addition for the ASSIGN statement

The use of implicit casting is prone to errors and results in source code that is difficult to understand. If the
CASTING addition is used when handling field symbols, explicit casting can be implemented, which is easier to
follow and understand. The explicit casting option is a very important reason to use field symbols.

5.2.9.3.1 Bad example

The following source code shows the assignment of a text string to a structure with only character-like
components. An implicit casting occurs here, which is regarded as undesirable according to the above rule. The
entire structure is handled as a text field of type c and length 6.

TYPES: BEGIN OF structure,


comp1 TYPE c LENGTH 2,
comp2 TYPE c LENGTH 4,
END OF structure.
DATA structure TYPE structure.
DATA text TYPE string.
... text = ...
structure =
text.

5.2.9.3.2 Good example

The following source code improves the example above, by assigning the structure to a field symbol of type c.
Explicit casting occurs. Only the character-like field symbol is used to handle the structure as a character-like
field.

...
FIELD-SYMBOLS <text> TYPE c.
...
ASSIGN structure TO <text> CASTING.
<text> = ...

Runtime Errors When Accessing Data Objects

5.2.10.1 Background

Using data objects can cause runtime errors if the data object contains unsuitable content or the access to the
data object is unsuitable. Examples:

• Assigning values outside the value range of a target variable

Page: 159 of 227


• Using values that cannot be converted to the required type. In other words, a conversion rule exists but
the source field content is not convertible. For example, you are trying to assign a character field (with
content that cannot be interpreted as a number) to a numeric field.

• Access to parts of data objects (subfield access). Either offset access/length access or the use of
predefined subfunctions such as substring.

5.2.10.2 Rule

Preventing Runtime Errors When Accessing Data Objects

You need to prevent runtime errors that can occur when accessing data objects. Robust applications should
always be programmed to avoid these errors.

5.2.10.3 Details

If it not possible to determine by filling data objects appropriately whether subsequent access causes errors,
then either the relevant properties must be checked before data access or possible exceptions (subclasses of
CX_SY_CONVERSION_ERROR or CX_SY_DATA_ACCESS_ERROR) must be caught during data access.

5.2.10.3.1 Bad Example

The following source code illustrates a typical situation that can easily cause a runtime error if the subarea
defined by offset and length is not defined in text.

DATA text TYPE string.


... substring =
text+offset(length).
...

5.2.10.3.2 Good Example

The following two source codes illustrate how the above example can be changed to avoid runtime errors using
prevention or exception handling.

IF strlen( text ) > offset + length.


substring = text+offset(length).
ELSE.
...
ENDIF.
TRY.
substring = text+offset(length).
CATCH cx_sy_range_out_of_bounds.
...
ENDTRY.

Anonymous Containers

5.2.11.1 Background

Anonymous containers are character-like or byte-like data objects of type c or string type (or x/xstring type).
Data objects of other types (especially structures) are assigned using casting to these objects, to store them
persistently in these containers.

Page: 160 of 227


5.2.11.2 Rule

Do not use character or byte fields as containers

Do not store structured data in unstructured character-like or byte-like variables.

5.2.11.3 Details

The direct storage of structured data in unstructured character-like or byte-like data objects is problematic,
particularly with data exchanges using remote function calls (RFC), input/output through the file system or
output to a printer. Unexpected results can occur due to platform-specific byte orders (endianness), alignment
requirements and different character sets (codepage).

For example, if a container is stored and imported to an application server with a different byte order, problems
will occur if the container is used for content for which the byte sequence is critical. In other words, the numeric
fields of types i, decfloat16, decfloat34 and f. In Unicode systems, the byte order of character-like data objects
also depends on the platform.

Even without these technical problems, it can difficult to correctly import data that has been stored as described
above. You usually have to perform another casting operation for the data type of the data stored in the
container. However, as the relevant type information is not saved with the data, it might not be possible to
perform type-specific casting.

5.2.11.3.1 Note

If you need to store data in an unstructured container, you can use the EXPORT ... TO DATA BUFFER
statement. This type of data storage is robust compared to different platform properties. However, you cannot
use EXPORT and IMPORT to directly process reference variables or instances referenced by them. As a
workaround, you can serialize these variables and instances for storage by using the CALL
TRANSFORMATION statement. A class must include the IF_SERIALIZABLE_OBJECT tag interface, so that its
objects can be serialized using CALL TRANSFORMATION.

Pass by Reference of Global Data

5.2.12.1 Background

In a local context you can normally directly access the data objects of superordinate more global contexts. For
example, in a method, you can have write access to the attributes of the specific class and to the potential
global data of the current program.

Therefore, if a more global data object is passed to a procedure by reference, access is granted there both
through its name and the formal parameter.

5.2.12.2 Rule

Do Not Pass Global Data to Local Contexts by Reference

Do not use global data as actual parameters for formal parameters of procedures if you can change them in the
procedure in another way, and the parameter is passed by reference.

5.2.12.3 Details

Page: 161 of 227


If a global data object that has also been passed by reference is changed in a procedure (method), this also
changes the formal parameter and vice versa. This behavior is not usually anticipated when writing the
procedure.

Global data is only supposed to be transferred to formal parameters for which pass by value is declared, or to
procedures that are guaranteed not to have any unwanted consequences for this data.

5.2.12.3.1 Bad example

After the do_something method has been called in the main method in the following source code, the attr
attribute contains the unexpected value 2.0, because the first assignment to the c_value changing parameter,
which has been passed by reference, also changes attr.

CLASS class DEFINITION.


PUBLIC
SECTION.
METHODS
main.
PRIVATE SECTION. DATA attr TYPE p
DECIMALS 2. METHODS do_something
CHANGING c_value TYPE numeric.
ENDCLASS.
CLASS class IMPLEMENTATION.
METHOD main. attr = '1.23'.
do_something( CHANGING c_value = attr ).
ENDMETHOD.
METHOD do_something.
... c_value =
floor( attr ).
... c_value = c_value
+ attr.
...
ENDMETHOD.
ENDCLASS.
5.2.12.3.2 Good example

If the pass by reference method in the method declaration of do_something in the above example is converted
into a pass by value method, as shown in the following source code, the attr attribute contains the expected
value 2.23 after the method has been called.

...
METHODS do_something CHANGING
VALUE(c_value) TYPE numeric.
...

5.3 Systems Fields


An ABAP program can request the status of the ABAP runtime environment using the system fields. From a
technical viewpoint, these system fields are a set of predefined variables - the components of the predefined sy
structure of data type SYST from the ABAP Dictionary - that are always available while the program is running.

The system field sy-repid is an exception. This field indicates the name of the program currently running. In this
case, we are dealing with a predefined constant and not a component of the predefined sy structure.

Page: 162 of 227


Access

5.3.1.1 Background

The system fields are supplied with values by the ABAP runtime environment. In a program, however, they
behave like normal variables. You can assign values to these fields using the ABAP program. This is because
both the ABAP kernel and the ABAP components of the ABAP runtime environment have write access to
system fields.

5.3.1.2 Rule

Do not write to system fields

Only use read access and never write access to access system fields in an application program.

5.3.1.3 Details

The values of system fields are usually vital for correct program execution. Therefore, write access to system
fields carries a lot of risk. Write operations in system fields can lead to a loss of important information, which
can prevent programs from running correctly. Therefore, you cannot overwrite system fields to change the
execution of the program or use the fields to replace explicitly defined variables.

In addition, you cannot misuse system fields as implicit output parameters of procedures, irrespective of
whether the fields have been explicitly set within the procedure (due to a prohibited write access or as the result
of an executed statement).

5.3.1.3.1 Exception

The only system fields where it was permitted to change the field content (in an application program) belong to
classical list processing. This should no longer be used.

5.3.1.3.2 Bad example

The following source code shows a write access to the sy-subrc system field, which occurs frequently. This write
access is not harmful but it also is not beneficial: sy-subrc is always set to zero when a function module is
called and only adopts a different value by handling a classical exception. Therefore, the statement is
redundant.

sy-subrc = 4.
CALL FUNCTION ...
...
EXCEPTIONS ...
CASE sy-subrc.
...

5.3.1.3.3 Good example

The source code below omits the write access shown above.

CALL FUNCTION...
...
EXCEPTIONS ...
CASE sy-subrc.
...

Page: 163 of 227


Obsolete and internal system fields

5.3.2.1 Background

Not all system fields are designed to be used in application programs. All available system fields can be
displayed as components of the structure SYST in ABAP Dictionary (or as components of the structure sy in the
debugger). The meaning of the components is included in the accompanying description. Any system fields that
are obsolete or only to be used internally are clearly marked.

5.3.2.2 Rule

Do not use obsolete or internal system fields

In application programs, do not use system fields flagged as obsolete or for internal use only in ABAP Dictionary
or in the ABAP documentation.

5.3.2.3 Details

The behavior of obsolete and internal system fields is undefined. This means that ABAP application programs
must not make any assumptions about the content of these system fields.

5.3.2.3.1 Bad example

The following source code shows how the system field sy-fodec, flagged for internal use, is used illegally in the
structure SYST after the statement DESCRIBE FIELD to count the number of decimal places in a data object.

DATA dobj TYPE p LENGTH 8 DECIMALS 2.


DATA type TYPE c LENGTH 1.
DATA decimal TYPE i.
DESCRIBE FIELD dobj TYPE type.
decimals = sy-fodec.

5.3.2.3.2 Good example

The following source code demonstrates how decimal places can be counted correctly using the appropriate
addition of the statement DESCRIBE FIELD.

DATA dobj TYPE p LENGTH 8 DECIMALS 2.


DATA type TYPE c LENGTH 1.
DATA decimals TYPE i.
DESCRIBE FIELD dobj TYPE type DECIMALS decimals.

Evaluation

5.3.3.1 Background

System fields describe general system states or are set specifically by individual statements. The content of
system fields is only defined as described in the documentation of the system fields or in the documentation of
ABAP statements that set system fields. In contexts other than those described there, the content of system
fields is not defined. Particularly statements for which no effect on system fields is documented can affect the

Page: 164 of 227


content of specific system fields, such as the return value sy-subrc, in an undefined way. This applies especially
to statements that call ABAP code implicitly or explicitly when executed.

5.3.3.2 Rule

Evaluate system fields in the right position

Evaluate system fields only in contexts for which they are defined. If an ABAP statement sets a system field in
accordance with its documentation, the field should be evaluated directly after the statement. You must not
evaluate system fields after statements, however, for which no effect is documented.

5.3.3.3 Details

If possible, a system field should be evaluated directly after the statement that set it, to prevent it from being
overwritten by other statements. The bigger the gap between the ABAP statement in question and the
evaluation of a system field, the higher the risk that this system field will be influenced by a different statement
in the meantime.

If necessary, the values of system fields should be saved in auxiliary variables. This applies in particular to the
general return value, sy-subrc, which is set by very many different statements. Other common examples include
the syindex loop counter or the sy-tabix table index.

You should never evaluate statement-related system fields after statements that do not set these fields
according to their documentation. As before, a common example is the evaluation of sy-subrc. If it is not
documented for a statement that it sets sy-subrc in a defined way, an evaluation after this statement is very
risky. Either sy-subrc still has the previous value, or it is set in an undefined way by the statement. Both
outcomes can lead to incorrect program behavior. The bad example in the extended program check section
shows an example of this.

5.3.3.3.1 Note

The static methods of the class CL_ABAP_SYST also provide important system states. There is no possibility of
a previous overwriting in the program.

5.3.3.3.2 Bad example

The following source code shows an example where sy-subrc is evaluated too late. Even if it is not documented
for the statements between FIND and IF that they set sy-subrc, the value can be overwritten due to possible
side effects.

FIND REGEX ... IN ...


...
... "other statements
...
IF sy-subrc = 0.
...
ENDIF.

5.3.3.3.3 Good example

The following source code corrects the above example by assigning sy-subrc to a helper variable directly after
FIND. This variable is then evaluated in IF. It can also be necessary to assign sy-index or sy-tabix to a helper
variable directly after DO or LOOP loop is entered.

Page: 165 of 227


FIND REGEX ... IN ...
find_subrc = sy-subrc.
...
... "other statements
...
IF find_subrc = 0.
...
ENDIF.

Return value

5.3.4.1 Background

The most prominent system field should be the return code sy-subrc. This indicates the successful execution of
an ABAP statement or, if using classic exceptions are used, a procedure. A return code of 0 usually means that
the execution was successful.

5.3.4.2 Rule

Evaluate the return code sy-subrc

Evaluate the return code sy-subrc after every ABAP statement that sets the value according to the
documentation. However, sy-subrc should never be set after statements are executed for which the setting of a
return value is not documented.

5.3.4.3 Details

The system field sy-subrc indicates whether a statement was successfully executed. If the execution was not
successful, the program should usually react accordingly. If this does not happen, the program's response will
probably be unexpected.

This rule is a specialization of the more general rule evaluate system fields in the correct place. It is listed here
again separately due to the prominent role of the return code sy-subrc. The system field sy-subrc must always
be evaluated immediately and, if necessary, assigned to a help variable. An evaluation cannot occur after
statements that set sy-subrc not defined, because otherwise wrong conclusions could easily be drawn.

5.3.4.3.1 Note

Special care must be taken in functional method calls. If executed successfully, each method call sets the return
code sy-subrc to 0, which means that functional method calls overwrite the return code when used in
statements where the setting of the return code is not documented. The same applies to the instance operator
NEW when instances of classes are created.

5.3.4.3.2 Exception

If a handling action seems unnecessary because, in the developer's opinion, the statement is always executed
successfully, the assumption should at least be saved and documented using an assertion.

5.3.4.3.3 Bad example

The following source code shows how further processing of data is performed using the work area of a SELECT
command, without a request from sy-subrc. However, the content of wa is usually undefined here, if a request
from sy-subrc does not guarantee that database access will be successful.

Page: 166 of 227


SELECT ...
INTO wa
...
... "work with wa

5.3.4.3.4 Good example

The following source code corrects the above example. This means the successful execution of the SELECT
statement is checked.

SELECT ...
INTO wa
...
IF sy-subrc <> 0.
...
ENDIF
... "work with wa

Use as current parameter

5.3.5.1 Background

The structure sy exists once in an internal session and is shared by all programs in this internal session. The
components of sy represent the system fields. System fields are global for all programs of an internal session
and their procedures.

5.3.5.2 Rule

Do not use system fields as actual parameters

Never use system fields as actual parameters - especially not for passing by reference.

5.3.5.3 Details

This rule reinforces the rule do not pass global data to local contexts by reference. Since system fields are set
implicitly, it is important to be even more careful. If the value of a system field changes implicitly within a
procedure, the value of the parameter passed by reference, which refers to this system field, also changes.
Procedures are never prepared for this behavior.
Even pass by value should be avoided for system fields. This is because a procedure might be switched to pass
by reference in an enhancement process, without the user of the procedure being notified. The only secure
method is to assign the value of a system field to a normal variable and then use this variable as the actual
parameter when calling the program.

5.3.5.3.1 Bad example

Looking at the method do_something in the following source code, it could be expected that the parameter
index in the loop to contain the unchanged value that was passed to the procedure. In fact, index references sy-
index, which is set to the current loop counter in the DO loop.

CLASS class DEFINITION.


PUBLIC SECTION.
METHODS main.
PRIVATE SECTION.

Page: 167 of 227


METHODS do_something IMPORTING index TYPE i.
ENDCLASS.
CLASS class IMPLEMENTATION.
METHOD main.
DO 2 TIMES.
do_something( sy-index ).
ENDDO.
ENDMETHOD.
METHOD do_something.
DO 3 TIMES.
... index ... .
ENDDO.
ENDMETHOD.
ENDCLASS.

5.3.5.3.2 Good example

The following source code corrects the call of the do_something method. A helper variable is passed with the
corresponding value instead of sy-index.

...
CLASS class IMPLEMENTATION.
METHOD main.
DATA index TYPE sy-index.
DO 2 TIMES.
index = sy-index.
do_something( index ).
ENDDO.
ENDMETHOD.
...
ENDCLASS.
...

Using system fields on the user interface

5.3.6.1 Background

As system fields are defined using the syst structure in ABAP Dictionary, you can technically use them to define
input fields in dynpros/in Web Dynpro.
5.3.6.2 Rule

Do not use system fields on the user interface

Never use system field types to define input or output fields for dynpros or selection screens in application
programs.

5.3.6.3 Details

This rule is derived from the SoC rule and the use of data types rule. System fields are purely technical. Their
semantic properties, are defined in the ABAP Dictionary (documentation and other texts), do not allow
meaningful use in the user dialogs of application programs.

5.3.6.3.1 Note

Page: 168 of 227


Similarly, you can apply the rule only use semantically appropriate data types to the use of SYST structure
components (for typing interface parameters of procedures). The semantic meaning of a system field
(expressed in the short text) does not generally match the meaning of the parameter.

5.3.6.3.2 Example

When the program PGL_SYSTEM_FIELD_ON_UI is executed, input fields for document output language are
displayed on a classical dynpro. The first input field is declared with reference to data type syst-langu of system
field sy-langu. The second input field is declared with reference to a semantically suitable ABAP Dictionary data
type. The displayed F1 help clearly indicates that syst-langu is not suited for language fields in a user dialog.
This is because the help only describes the behavior of the sy-langu field in a program. It does not describe the
meaning of the language field in the relevant application.

Use in operand positions

5.3.7.1 Background

Statements that modify the content of system fields generally evaulate the operands first and then set the
system fields. In some complex statements, however, a system field could be set first, before all operand
positions are evaluated.

5.3.7.2 Rule

Do not use system fields in statements that set the fields

For reasons of robustness, do not use system fields as operands of statements that themselves set these
system fields.

5.3.7.3 Details

A program does not always define whether a particular system field is set in a statement before or after an
operand is evaluated. This means that, to reduce risks and to make the program easier to read, the content of
a system field should always be copied to an auxiliary variable and only this copy should be used within the
statement in question. 5.3.7.3.1 Note
Also take note of how functional methods are used in operand positions. These methods also modify important
system fields. Also be careful here when using system fields in operand positions of the same statement.
5.3.7.3.2 Bad example

The following source code shows how the system field sy-tabix is used in a READ statement that sets the
system field itself. The case shown here does not itself present any difficulties, however we still recommend you
follow the rule above, not least to make the code more readable.

LOOP AT itab1 ... WHERE ...


...
READ TABLE itab2 ... INDEX sy-tabix.
...
ENDLOOP.

5.3.7.3.3 Good example

Page: 169 of 227


The following source code makes the example above more robust by assigning the value of the system field
sytabix to an auxiliary variable before it is used.

LOOP AT itab1 ... WHERE ...


index = sy-tabix.
...
.... itab2[ index ] ...
...
ENDLOOP.

5.4 Internal Tables


An internal table is a dynamic data object consisting of a sequence of rows with the same data type. The data
type of an internal table is a table type that has the following basic properties of every internal table:

• Row type

The row type can be any data type. In particular, tables of


elementary types, tables of structures, tables of tables, and
tables or references are all possible.

• Table category

The table category specifies the type of storage and primary access. The possible table categories are:

o Standard tables administered using a primary table index and which cannot have a unique primary
table key.

o Sorted tables administered using a primary table index and that can have a unique or non-unique
primary table key (used to sort the table).

o Hashed tables whose primary table key always has to be unique and which use a hash algorithm
(distributed memory management) to administer their rows. A hashed table does not have a
primary table index.

• Primary table key


Every internal table has a primary table key. A table key consists of columns from the internal table. The
content of these columns identifies table rows. The table category determines whether a key is unique
or non-unique.

Internal tables enable variable datasets (a variable number of rows) with a fixed structure (the row type) to be
edited in the working memory of the internal session of a program. The content of an internal table can either be
accessed sequentially in a LOOP or by accessing individual rows (for example, by using READ TABLE or a
table expression).

There are two ways of accessing individual rows:

• By specifying a key (a table key or a free key)

• By specifying a row index

Page: 170 of 227


Primary table access is possible for all three table categories. Access using the primary key, however, is
optimized only for sorted tables and hashed tables. In standard tables, primary key access uses a linear search.
Access using the primary row index, on the other hand, is possible for standard tables and sorted tables only.
As well as its primary key, an internal key can also have further secondary keys. These keys enhance and
optimize access options to the various table categories.

Selecting the Table Category

5.4.1.1 Background

The table category specifies the internal administration for an internal table and the primary access type:

• Standard tables that are managed with a primary table index. When inserting or deleting table rows,
only the table index is reorganized, but not the remaining table rows. If rows are only appended
(APPEND) at the end or deleted, no reorganization of the table index is required. However, access
using the primary key is not optimized. It triggers a linear search across all rows.

• Sorted tables are also managed using their primary table index, which is always available in the
memory, sorted according to the primary table key. This means that the table index must usually be
reorganized each time a table row is inserted or deleted. When accessing via the primary key, the
search is performed in binary format, causing the time required for the search to be merely
logarithmically dependent on the number of rows.

• Hashed tables are based on distributed memory management. They are therefore optimized for access
via the primary table key and attain a constant access time, irrespective of the number of lines. In
return, the distributed memory management requires additional memory space and does not allow for
nonunique primary table keys. There is no primary table index, and a respective index access is not
possible.

Standard tables and sorted tables can be summarized under the term index tables. An index access is always
the fastest way to access table entries. The prerequisite for an index access is that the value for the index
specification has been determined in advance. This usually requires a previous key access, for example, via
READ TABLE, where the sy-tabix system field is set.

5.4.1.2 Rule

Use a suitable table category

Select the table category according to the primary requirements. As a rule of thumb, if the tables are large, the
following selection criteria apply:
• Mainly index accesses: standard tables

• Index accesses and key accesses: sorted tables

• Only key accesses: hashed tables

5.4.1.3 Details

Particularly for tables with a lot of rows, you have to select the appropriate table category carefully. The
following recommendations are mainly derived from the processing speed requirements:

• Standard Tables

Page: 171 of 227


This table category can always be used if the primary access types are sequential processing or index
access. You should fill standard tables by appending lines using APPEND and implement the other
accesses using an index specification (INDEX addition of the respective statements). Ideally, the filling
process is decoupled from other accesses. After explicit sorting has taken place, you can also use an
optimized key access (free key) using BINARY SEARCH, which enables you to identify an entry point
for sequential processing (LOOP), for example. However, due to the linear search, large standard
tables (more than 100 rows) are not the appropriate table category, if the primary access type for an
internal table is through key accesses.

• Sorted Tables
This table category is useful if both a fast key access and an index access are necessary, and if the
rows are supposed to be sorted when the table is filled. In addition, sorted tables are also suited for
partially sequential access in a LOOP loop, where the first part of the table key is specified in the
WHERE condition. Finally, sorted tables with an ambiguous key are the only alternative to hashed
tables if no unique key can be defined.

• Hashed Tables
This table category is useful if key accesses are the central operation for table entries, if the tables are
large, and if a unique key can be defined.

In addition to the processing speed, memory requirements can also play an important role. If this is supposed to
be optimized according to Consider the Ratio of Administration and Application Data, you must also take into
account the administration costs of the table categories.

• Standard tables and sorted tables (index tables) that are managed via a table index, incur the least
administration costs (6 bytes for each line on average). As long as the logical order in the table index
corresponds to the physical order in the table body, a standard table does not incur any line-related
administration costs. This is the case if you always append lines after the last line or delete only the last
line.

• Hashed tables require considerably more space for their administration data than index tables (18 or 30
bytes for each line on average).

Depending on the length of the key and the number of lines in an internal table, the access via a sorted key can
be as fast as or even faster than using a hashed table. In such a case, and if the memory space is critical, you
should work with a sorted table instead of a hashed table.

If you use secondary keys, the rules mentioned here may be qualified to a certain degree, as the overall costs
need to be considered in this case.

Secondary Keys

5.4.2.1 Background

You can declare secondary keys for internal tables. The following options are possible:

• Sorted keys (non-unique or unique)

• Hash keys that can only be unique

These keys are assigned a name when they are declared and can be created for any table type. The primary
key (nameless up to this point) is assigned a predefined name (primary_key), which allows it to be explicitly
addressed. A secondary table index is created internally for each sorted secondary key. This enables index
access to hashed tables. When accessing internal tables, you must specify which table key or index should be

Page: 172 of 227


used. If nothing is explicitly specified, the internal table is accessed using the primary key or primary index by
default.

Access to internal tables using secondary keys is always optimized. This generally increases read access
performance significantly. Previously, no optimized key access was possible for this. On the other hand,
secondary keys also incur additional administration costs due to memory consumption and runtime. Additional
runtime costs arise, if a secondary table index needs to be updated after changes to table content. The ABAP
runtime environment delays these runtime costs for as long as possible, until they are actually required (lazy
update and delayed update). The administration costs for a secondary key are just as high as for the primary
table keys: on average, 6 bytes for each secondary index row and 18 or 30 bytes for each hash key row. On
average, another 8 bytes per row are required, if the table has at least one non-unique sorted secondary key.
Additional memory costs are generated, if a secondary key needs to be updated after changes to internal table
content. These memory costs are on the same scale as the costs above and also depend on the number of
rows.

5.4.2.2 Rule

Use secondary keys in a way that benefits the table.

Use secondary keys sparingly and only in cases where the benefits outweigh the extra costs.

5.4.2.3 Details

The internal management of secondary keys in an internal table can involve significant memory consumption
and updates. Secondary keys are useful for accelerating read access in the following cases:

• The standard scenario for sensibly using secondary table keys relates to a very large internal table that
is filled once and the content is changed very infrequently. In this case, runtime costs for secondary key
administration are only generated when the internal table is created and in a few other rare situations.
These costs are more than outweighed by more efficient, more frequent read access.

• Secondary keys might be useful for small internal tables in some circumstances because they ensure
unique table entries in relation to particular components. This justifies the extra costs for the secondary
key. This applies to standard tables in particular, whose primary keys can never be unique.

When using secondary keys, remember:

• As a matter of principle, secondary hash keys should not have too many components. Otherwise, the
system has to deal with a high system load caused by the additional hash management. Sorted keys
are preferable for secondary keys with a large number of components. The same applies to primary
keys.
• In the case of pure read access where unique table entries are not relevant, non-unique secondary
keys are usually sufficient. Read access is just as fast as for unique keys (or nearly as fast if duplicate
entries exist). Updates are only performed after table modifications if necessary.

• If index table rows are deleted using secondary key accesses, the primary index of the table must be
updated. This cannot be optimized for standard tables; a linear search needs to be performed instead.

You should not use secondary table keys in the following situations:

• For small internal tables (less than 50 rows), the performance gain for read accesses is greatly
outweighed by the increased memory and administration costs.

Page: 173 of 227


• With tables that are subject to a large number of write accesses, the load incurred by updating the
secondary keys outweighs the performance benefit for read accesses. Delayed updates and lazy
updates in particular can generate update costs for precisely those read accesses for which the
optimization was actually intended. This results in either no gain or a negative gain.

5.4.2.3.1 Note

It is relatively easy to provide secondary keys later on for existing internal table types in ABAP programs. And it
is especially easy to provide secondary keys later on for table types that are defined in the ABAP Dictionary.
Remember that — contrary to database accesses — you must explicitly specify the secondary key of an
internal table at the where-used position. Otherwise, it is not evaluated. In these cases, you should usually only
define non-unique sorted keys. Otherwise, programs that use tables of this type (and populate these tables with
nonunique rows based on this component) will no longer function properly.

Note that the sy-tabix system field is populated by the assigned secondary index, if sorted secondary keys are
used. If this value is used for the subsequent index access to the internal table, the same table index must be
explicitly used here. If used implicitly, the value would be interpreted as a primary index.

5.4.2.3.2 Bad Example

In the following source code, a large hashed table is accessed using a free key, which does not correspond to
the table’s primary key. Therefore, a linear search is required for this access. This is very time-intensive.

DATA itab TYPE HASHED TABLE OF dbtab


WITH UNIQUE KEY col1 col2 ... "fill itab
with a large amount of data
...
READ TABLE itab
WITH KEY col3 = ... col4 = ...
ASSIGNING ...

5.4.2.3.3 Good Example

The following source code optimizes the above example by adding a secondary table key to the table
declaration. This key replaces the free key during access. Sequential processing (in the order defined with this
key) can now be performed.

DATA itab TYPE HASHED TABLE OF dbtab


WITH UNIQUE KEY col1 col2 ...
WITH NON-UNIQUE SORTED KEY
second_key COMPONENTS col1 col2 ... "fill
itab with a large amount of data
...
ASSIGN itab[ KEY second_key
COMPONENTS col3 = ... col4 = ... ]
TO ...
...
LOOP AT itab USING KEY second_key.
...
ENDLOOP.

Initial Memory Requirements

5.4.3.1 Background

Page: 174 of 227


Internal tables are stored in the memory block by block. The ABAP runtime environment allocates a suitable
memory area for the data of the table by default. If the initial memory area is insufficient, further blocks are
created using an internal duplication strategy until a threshold is reached. After this, all blocks are requested
with a constant size between eight and 16 kilobytes.

The INITIAL SIZE addition is used to predefine a number of table rows when declaring an internal table, to
override the number of initially allocated rows set by the system.

5.4.3.2 Rule

Modify the initial memory requirements only for nested tables

Only use the INITIAL SIZE addition for the declaration of inner tables in nested tables if you can avoid using a
large amount of memory unnecessarily.

5.4.3.3 Details

The INITIAL SIZE addition is not necessary for external or non-nested tables since the automatic memory
location by the runtime environment leads to the required result. Automatic memory allocation only results in
excessive memory consumption in nested inner tables if more memory is allocated for a number of inner tables
than they actually use. If the number of entries in the inner tables is known from the outset, the initial main
memory requirement can be set accordingly using INITIAL SIZE.

5.4.3.3.1 Note

Instance attributes of classes that are declared as inner tables can also be considered as nested tables. If many
instances of a class with tabular attributes are expected, it can be useful to specify INITIAL SIZE.

5.4.3.3.2 Bad example

The following source text shows the declaration of a nested table, where the initial memory requirement is
specified incorrectly for the outer large table, not the inner small table.

TYPES small_table TYPE STANDARD TABLE OF ...


WITH NON-UNIQUE KEY ...
TYPES: BEGIN OF line_structure,
...
int_table TYPE small_table,
...
END OF line_structure, big_table TYPE
SORTED TABLE OF line_structure WITH
UNIQUE KEY ... INITIAL SIZE 10000.
5.4.3.3.3 Good example

The following source text shows the declaration of a nested table, where the initial memory requirement is
specified according to the above rule: for the inner small table and not the outer large table.

TYPES small_table TYPE STANDARD TABLE OF ...


WITH NON-UNIQUE KEY ...
INITIAL SIZE 4.
TYPES: BEGIN OF line_structure,
...
int_table TYPE small_table,
...

Page: 175 of 227


END OF line_structure, big_table TYPE
SORTED TABLE OF line_structure WITH
UNIQUE KEY ...

Sorted Filling

5.4.4.1 Background

The statement APPEND for attaching rows to an internal table has the addition SORTED BY. This addition can
be used to fill a standard table by using sorted filling. The prerequisites are:

• A value greater than zero must be specified for the addition INITIAL SIZE.

• Only the APPEND statement with the SORTED BY addition can be used to fill the internal table.

Once these prerequisites have been met, a ranking list is generated that contains at most the same number of
rows as specified with INITIAL SIZE. This list is sorted by the component specified after SORTED BY in
descending order.

5.4.4.2 Rule

Create ranking lists with unsorted filling

Do not use the SORTED BY addition of the APPEND statement to generate ranking lists. Use the SORT
statement instead.

5.4.4.3 Details

If the APPEND statement is used with the SORTED BY addition, you cannot simply append rows (contrary to
what the name implies). Instead, a complicated process is started that only generates a ranking list if specific
prerequisites are met. Otherwise incomprehensible results are returned. In addition, it is not possible to sort by
more than one column.

The SORT statement is more robust, more powerful and easier to comprehend when used in this scenario.

5.4.4.3.1 Bad Example

The following source code shows how to create a ranking list of the ten longest distances from a table of flight
connections, by using the rule APPEND SORTED BY. This rule is no longer recommended, as described
above. When declaring the ranking list table, you need to specify the addition INITIAL SIZE.
...
DATA distance_list TYPE TABLE OF spfli-distance
INITIAL SIZE 10.
FIELD-SYMBOLS <spfli_wa> LIKE LINE OF spfli_tab.
...
LOOP AT spfli_tab ASSIGNING <spfli_wa>.
APPEND <spfli_wa>-distance TO distance_list
SORTED BY table_line.
ENDLOOP.
...

5.4.4.3.2 Good Example

Page: 176 of 227


The following source code shows how to create the same ranking list in the previous example, but using the
more robust statement SORT.

...
DATA distance_list TYPE TABLE OF spfli-distance.
FIELD-SYMBOLS <spfli_wa> LIKE LINE OF spfli_tab.
...
SORT spfli_tab BY distance DESCENDING.
LOOP AT spfli_tab TO 10 ASSIGNING <spfli_wa>.
APPEND <spfli_wa>-distance TO distance_list.
ENDLOOP.
...

Compressed Filling

5.4.5.1 Background

The statement COLLECT can be used to collect rows and insert them in an internal table. If a row with the
relevant primary key already exists in the target table, the values of numeric components are added to the
values in the existing table row. Otherwise, a new row is inserted in the table.

5.4.5.2 Rule

Do not fill standard tables with collections of rows

Only use the statement COLLECT for hashed tables or sorted tables with a unique key. Do not use it any more
for standard tables.

5.4.5.3 Details

The statement COLLECT is based on unique entries with respect to the primary key and stable key
administration. This means that not all categories of internal ables are suitable for COLLECT:

• If the statement COLLECT is applied to a standard table, this table first needs its own internal hash
administration. Change operations on the table can invalidate this temporary hash administration. After
a change operation of this type, the following COLLECT statements must resort to a linear search,
which can affect performance considerably. The primary key of a standard table is also never unique.

• COLLECT can be used for sorted tables and hashed tables without any problems since these, unlike
standard tables, always have a separate, stable key administration that can be utilized by COLLECT.
COLLECT can work properly for sorted tables only if the primary key is unique. If a sorted table has a
non-unique key, then only COLLECT can be used to fill the table, which is difficult to guarantee. In
hashed tables, the key values are always unique.

Output Behavior

5.4.6.1 Background

Page: 177 of 227


Internal tables can be read by accessing individual rows (using READ TABLE or table expressions) or
sequentially (using LOOP AT). In both cases, the following output behavior can be defined by using the
statements with the following additions:

• The addition INTO copies the content of the row to an appropriate data object.

• The addition ASSIGNING assigns the read row to a field symbol, which enables the row to be
addressed directly.

• The REFERENCE INTO addition sets a data reference to the read row.

In the case of table expressions, the output behavior is controlled by the category of the result.

As well as for exports, the ASSIGNING and REFERENCE INTO additions can also be used for the APPEND,
COLLECT, INSERT, and MODIFY statements, where they create references to the row being edited.

5.4.6.2 Rule

Choose appropriate output behavior

When reading rows of internal tables, select an appropriate output behavior. The rule of thumb is:

• Copy to a work area if the row type is narrow and the read row is not to be modified.

• Assign to a field symbol if the row type is wide or deep and the read row is to be modified.

• Set a data reference if the row type is wide or deep and a reference to the read row is to be passed.

5.4.6.3 Details

The criteria for selecting the output behavior are the processing speed, on the one hand, and what is to be done
with the read row, on the other hand:

• If the content of the read row is to be modified, the addition ASSIGNING or (in the case of table
expressions) the appropriate result should usually be used. This allows direct access to the row using
the value semantics and removes the need for a MODIFY operation later on.

• If a reference to the read row is required that can be processed using reference semantics, the
addition REFERENCE INTO or (in the case of table expressions) the appropriate result is to be used.

• If the content of the read row is not to be modified, any of these procedures can be used. The row type
of the table is significant for performance. If the table row is wide or contains deep components (for
example, strings or other tables), reads are usually faster if ASSIGNING or REFERENCE INTO is used
instead of INTO. The way they are used is the determining factor for selecting which of the two should
be used.

When working with tables whose rows are flat and do not occupy more than approximately 1KB,
copying with INTO is faster (at least for the READ statement) than configuring the administration that is
required for dynamic access. For the statement LOOP, these costs are incurred only once, so that
using ASSIGNING or REFERENCE INTO is always recommended above a certain number of rows. In
contrast, INTO should always be used if the target area is to be modified without this affecting the
internal table.

Page: 178 of 227


Besides the processing speed, it is also important that the source code can be understood. If the
recommendations mentioned are kept, reading a table with the addition ASSIGNING (but also REFERENCE
INTO) indicates to the reader that the table content is potentially changed. Reading a table with the INTO
addition, on the other hand, indicates that the table will not be modified.

For table expressions, the information here applies to the selection of the appropriate result.

5.4.6.3.1 Bad example

The following source code shows the assignment of rows of an internal table to a work area with the aim of
modifying the read rows. For this modification, however, an additional statement, MODIFY, is required, and two
unnecessary copy processes take place for each loop pass.

LOOP AT itab INTO wa.


...
wa = ...
MODIFY itab FROM wa.
ENDLOOP.

5.4.6.3.2 Good example

The following source code corrects the above example; here, a field symbol is used for direct access to modify
the read rows. No unnecessary copy costs are incurred.

LOOP AT itab ASSIGNING <fs>.


...
<fs> = ...
ENDLOOP.

Loop Processing

5.4.7.1 Background

Alongside the statements for editing individual rows in internal tables, other statements can be used to address
and modify the entire body of the table. Examples:

• All categories of assignments applying to whole internal tables

• Deleting the whole of an internal table using CLEAR or FREE

• Operations in target ranges such as SELECT INTO TABLE

These types of accesses to the table body cause problems by producing a loop across the internal table

Page: 179 of 227


Rule
5.4.7.2

Do not modify the entire table body in a loop

You cannot use a loop across an internal table to perform accesses to the table that modify the entire table
body at once.

5.4.7.3 Details

A modifying access to the entire table body usually produces a runtime error and at the very least unpredictable
program behavior. If this can be detected statically, a syntax error occurs within classes and also in LOOPs with
a statically detectable secondary key when the table operations in question are used. Otherwise, the syntax
check simply returns a warning for compatibility reasons.

5.4.7.3.1 Note

This rule is mainly intended to make you more away of the problem. If you only work with ABAP Objects or if no
syntax check warnings are ignored, then the rule above should be kept automatically.

5.5 Modularization units


Procedures can be:

• Methods

• Function modules

• Subroutines

Only procedures support parameter interfaces and have a local data context.

Dialog modules and event blocks do not have parameter interfaces and generally do not have a local data
context.

Macros are a kind of halfway house between callable units and source code modularization.

Function Modules and Subroutines

5.5.1.1 Background

Function modules and subroutines are the procedures of the structured programming model that already
existed before the introduction of ABAP Objects.

• Function modules in function groups are independent repository objects that the structured model
provides for external calls or for the provision of reusable functions.

• Before the introduction of ABAP Objects, subroutines could be created in any programs and were
intended for internal calls or for the internal modularization of programs in the structured model.

Page: 180 of 227


Rule
The introduction of ABAP Objects means that methods now have both roles.
5.5.1.2

No implementations in function modules and subroutines

Only use function modules and subroutines if they are necessary from a technical viewpoint. In these cases, do
not implement the required function. Instead, call the relevant (local) methods.

5.5.1.3 Details

This rule is directly derived from rule Use ABAP Objects. This rule states that only methods should be created.
You are only allowed to create other types of procedures if is technically not possible to use a method:

• Function modules for RFC, updates, and access to classical dynpros or selection screens

• Subroutines for PERFORM ON COMMIT/ROLLBACK and GENERATE SUBROUTINE POOL

These subroutines should only be used for wrapping method calls to ensure that ABAP Objects is also used in
these cases.

All the rules in these programming guidelines that relate to procedures actually refer to methods because,
strictly speaking, no other procedures with nontrivial code are supposed to occur. If you strictly adhere to the
above rule, is almost impossible for any of the rules that refer to implementations of procedures to be applied to
function modules and subroutines, because they only serve to wrap calls. For example, function modules and
subroutines should no longer contain any of the local declarations that are described in "Defining Local
Declarations at the Start of a Procedure".

If you cannot adhere to the rule "Use ABAP Objects" and the above rule because, for example, existing legacy
function modules and subroutines need to be maintained or enhanced and you cannot switch to methods, the
rules in these programming guidelines that refer to procedures also apply to function modules and subroutines.

Type of Formal Parameters in Procedures

5.5.2.1 Background

The parameter interface of a procedure consists of formal parameters and specifies the exceptions possible in
the procedure. The possible types of formal parameters are:

• Input parameter
Defined with IMPORTING in methods and function modules and with USING in subroutines.

• Output parameter
Defined with EXPORTING in methods and function modules.

• Input/Output Parameters
Defined with CHANGING in methods, function modules, and subroutines.

• Return codes
Defined with RETURNING in methods.

Page: 181 of 227


Rule
The actual behavior of a formal parameter, however, is in part determined by the combination of the parameter
type and the transfer type.
5.5.2.2

Choose the appropriate formal parameter type

Select a formal parameter type that corresponds to the parameter semantics:

• Input parameters for parameters that are evaluated but not changed in the procedure.

• Output parameters or return codes for parameters that are not evaluated but changed in the procedure.

• Input/output parameters for parameters that are evaluated and changed in the procedure.

5.5.2.3 Details

For the user of a procedure, the parameter types provide important information on how they are used in the
procedure and leads the user to expect the procedure to behave in a certain way. If you do not select a suitable
parameter type, this increases the risk of an inappropriate use.

• Pure input parameters should always have the IMPORTING type (or USING for subroutines). Be aware
that when using pass by reference, write access to an input parameter defined using USING is possible
without a syntax error being produced (as is the case with input parameters of methods or function
modules defined using IMPORTING). Yet another reason to not use subroutines.

• Pure output parameters should always be of the EXPORTING or RETURNING type.

• Parameters that are received and changed should always be of the CHANGING type. In particular, in a
procedure (method) you should not exploit the fact that an EXPORTING parameter (or a USING
parameter in the case of subroutines) passed by reference behaves (from a technical perspective) like
a CHANGING parameter.

Input parameters or input/output parameters that are not necessarily required for the execution of a procedure
should be defined as optional by using OPTIONAL or by specifying a DEFAULT value. Otherwise, calling
programs are forced to pass unnecessary parameters and create helper variables especially for this purpose.

A narrow parameter interface in line with a procedure with an appropriate number of statements only requires a
few input parameters and one return value. However, this cannot really be applied consistently in practice and
is therefore not set out as a rule here.

5.5.2.3.1 Note

Another parameter type are table parameters that can be declared for function modules and subroutines using
TABLES. Basically, they have the same effects as input/output parameters for internal tables. This parameter
type is obsolete and should no longer be used.

5.5.2.3.2 Bad example

The following source code shows a formal parameter that is declared as an output parameter using
EXPORTING, but is used in the method like an input/output parameter declared with CHANGING. This does not
correspond to the semantics that a calling program expects.

Page: 182 of 227


Rule
CLASS class DEFINITION.
PUBLIC SECTION.
METHODS do_something
EXPORTING e_parameter TYPE ...
ENDCLASS.

Page: 183 of 227


CLASS class IMPLEMENTATION.
METHOD do_something.
"evaluate e_parameter
...
"set e_parameter
...
ENDMETHOD.
ENDCLASS.

5.5.2.3.3 Good example

The following source code corrects the above example by declaring the parameter as an input/output parameter
with CHANGING according to its use.

CLASS class DEFINITION.


PUBLIC SECTION.
METHODS do_something
CHANGING c_parameter TYPE ...
ENDCLASS.
CLASS class IMPLEMENTATION.
METHOD do_something.
"evaluate c_parameter
...
"set c_parameter
...
ENDMETHOD.
ENDCLASS.

How Formal Parameters Are Passed

5.5.3.1 Background

Parameters can be passed to procedures either by reference or by value.

• Pass by reference
In the case of pass by reference, a reference to the actual parameter is passed to the procedure when
it is called. The procedure then works with the actual parameter. No local data object is created for the
actual parameter. Input parameters that are passed by reference cannot be changed in the procedure
(exception: USING parameters of subroutines).

• Pass by Value
In the case of pass by value, a type-specific local data object is created as a copy of the actual
parameter for the formal parameter. The system initializes output parameters and return values when
the procedure is started. Input parameters as well as input/output parameters receive the value of the
actual parameter. A changed formal parameter is only passed to the actual parameter if the procedure
is completed without errors.

IMPORTING parameters that are passed by reference are protected from explicit changes within the procedure.
This is not the case for the pass by value method. RETURNING parameters always require the pass by value
method.

5.5.3.2 Rule

Choose a suitable pass-by type

Page: 184 of 227


When selecting the pass-by type, consider both speed and security:

• Pass by value for small data sets for security reasons

• Pass by reference for large data sets for performance reasons

5.5.3.3 Details

The pass by reference method generally has a higher performance than pass by value because no values need
to be copied. This speed advantage can be noticed especially in the case of large parameters, such as internal
tables or strings, or in mass data processing. In the case of small, flat parameters, the pass by value method
usually does not lead to problems because the copy costs incurred are not high here. Furthermore, for strings
and internal tables, sharing takes effect in the case of pass by value. Consequently, only references are passed
here. The time-intensive copy process is skipped if the data objects involved are only to be read-accessed,
such as in the case of EXPORTING parameters that are filled within a procedure (method), and are not
modified by the calling program after the pass.

Despite the speed advantage, the pass by reference method can lead to problems due to the following aspects:

• EXPORTING parameters that are passed by reference are not initialized automatically. Therefore,
such parameters are not supposed to be read until the first value has been assigned to them.

• Write access to EXPORTING and CHANGING parameters with the pass by reference method work
directly with the actual parameters. Their values are also modified if the procedure (method) is left early
due to an exception.

• IMPORTING parameters that are passed by reference change if the actual parameter changes. The
actual parameter can change, for example, if it is a global variable or a system field.

If passing by value will not cause performance problems, that is, if small data sets are passed or sharing can be
used, you should use this method for security reasons. If speed is an issue, you should work with passing by
reference. In this case, you must consider the potential risks in the implementation of the procedure (method).

5.5.3.3.1 Example

See the example in the section about the Code Inspector. In this example, an internal table is passed by
reference due to performance reasons, while an elementary parameter is passed by value due to robustness
reasons.

Pass By Reference for Output Parameters

5.5.4.1 Background

When parameters are passed to a procedure by reference, this procedure directly uses the data object that has
been passed as a parameter. Its value is consequently determined by the calling program of the procedure.
Particular notice must be made of this behavior for EXPORTING parameters, whose value is (unlike the pass
by value method) not initialized when the procedure is called. After the procedure has started, an output
parameter that was passed by reference has the value of the supplied actual parameter.
5.5.4.2 Rule

Use Output Parameters with the Pass by Reference Method Correctly

Page: 185 of 227


Do not evaluate EXPORTING parameters that are passed by reference in a procedure (method) until a value
has been explicitly assigned.

5.5.4.3 Details

Because the value of an output parameter that has been passed by reference is undefined from the procedure’s
perspective, it cannot be evaluated within the procedure in a useful manner. Therefore, no assumptions can be
made regarding the content of the parameter until the first value has been assigned to it.

If a parameter like this is an internal table or a string, a simple write is not sufficient. First, an initialization must
be implemented. For example, if new rows are to be inserted in an internal table that is supposed to be
produced by reference, its current content needs to be deleted first. Pass by reference means that it cannot be
guaranteed that the table is actually empty when the procedure is started. The same applies to strings that are
filled using concatenation operations within the procedure.

5.5.4.3.1 Note

If the described properties are to be exploited for writable parameters that have been passed by reference in a
procedure (method), that is, a read is to be performed prior to the write or an existing dynamic data object is to
be extended, the appropriate formal parameter type must be specified, that is, input/output parameter
(CHANGING parameter).

5.5.4.3.2 Exception

Strictly speaking, optional output parameters that have been passed by reference must be initialized only if the
parameter is bound to an actual parameter when called. This can be determined using the IS SUPPLIED query.
The obsolete query, IS REQUESTED, in contrast, should no longer be used.

5.5.4.3.3 Example

The following source code shows how an internal table that, for performance reasons, is implemented by
reference is returned. For this reason, it cannot be declared as a RETURNING parameter. The tabular output
parameter is explicitly initialized at the beginning of the method before new lines are inserted.

CLASS class DEFINITION.


PUBLIC SECTION.
CLASS-METHODS get_some_table
EXPORTING e_some_table TYPE table_type.
ENDCLASS.
CLASS class IMPLEMENTATION.
METHOD get_some_table.
DATA new_line LIKE LINE OF e_some_table.
CLEAR e_some_table.
...
INSERT new_line INTO TABLE e_some_table.
...
ENDMETHOD.
ENDCLASS.

Typing of Formal Parameters

5.5.5.1 Background

The typing of formal parameters can be complete or generic. Formal parameters of methods must be, and
formal parameters of function modules and subroutines should be, explicitly typed using the TYPE or LIKE

Page: 186 of 227


addition. When you connect actual parameters to formal parameters, the system checks whether the data type
of the actual parameter corresponds to the typing of the formal parameter.

• Complete typing completely defines the data type of a formal parameter and applies to both dynamic
access and static access to the formal parameter.

• Generic typing does not completely define the data type of a formal parameter. Instead, the actual data
type of the supplied actual parameter is used. For dynamic access to such a formal parameter, the
properties of the actual parameter apply. For static access, the properties that are defined by the typing
apply.

For generic typing, a set of predefined generic types is available in ABAP, which are only intended for the typing
of formal parameters and field symbols. Using them in any other way can lead either to errors or to missing
properties being completed with default values. The generic types are: any, any table, c, clike, csequence, data,
decfloat, hashed table, index table, n, numeric, object, simple, sorted table, standard table, table, x, and
xsequence. Self-defined table types without completely specified table key are also generic.

5.5.5.2 Rule

Be as specific as possible when typing formal parameters

Be only as generic as necessary when typing formal parameters. Completely generic types (any) should be the
exception rather than the rule. When used, a formal parameter must be compliant with all possible fixed types.

5.5.5.3 Details

Absolute type security within a procedure can only be achieved with complete typing. It should always be used
when providing a generic service is not a defined goal. It is much easier to carry out tests for non-generic
services than for generic services.

A generically typed procedure interface usually involves more implementation effort within the procedure
(method) to avoid runtime errors. Therefore, use the following principle when providing generic interfaces: as
little generic typing as possible and as much generic typing as necessary. You should use specific generic
types, such as numeric or csequence, instead of any or data, for example, if services are involved that are
supposed to process numeric values or character strings. If csequence is used, the potential fixed types c and
string must display different behavior with respect to trailing blanks or the potential numeric types in calculations
for numeric must produce different calculation types. More specifically, when existing typings are generalized, it
may be necessary to modify the implementation accordingly.

Generic typing can be a pitfall if you are not aware that you have used generic typing instead of complete
typing, because only the technical type properties are checked when an actual parameter is connected, but no
component names, for example. This can lead to different behavior than expected. 5.5.5.3.1 Note

These rules for typing also apply to field symbols.

5.5.5.3.2 Bad example

The following method shows different behavior when a blank is passed as a string of the type string or as a text
field of the type c.

CLASS demo DEFINITION.


PUBLIC SECTION.
CLASS-METHODS main IMPORTING flag TYPE csequence.
ENDCLASS.

Page: 187 of 227


CLASS demo IMPLEMENTATION.
METHOD main.
IF flag = abap_false.
...
ENDIF.
ENDMETHOD.
ENDCLASS.

5.5.5.3.3 Good example

Using the predefined function condense produces the same behavior when a blank is passed, regardless of the
fixed type.

CLASS demo DEFINITION.


PUBLIC SECTION.
CLASS-METHODS main IMPORTING flag TYPE csequence.
ENDCLASS.

CLASS demo IMPLEMENTATION.


METHOD main.
IF condense( flag ) = abap_false.
...
ENDIF.
ENDMETHOD.
ENDCLASS.

5.5.5.3.4 Bad example

The example in the following source code shows the trap you can fall into, particularly when working with table
types, if the table key is not completely specified in their declaration (in a program or in ABAP Dictionary). Due
to the missing key specification, the table type that is used to type the formal parameter of sort_itab is generic.
While the first static sorting is successful, the second SORT statement fails and triggers a runtime error. For the
dynamic component specification, the properties of the actual parameter apply to the formal parameter, and the
actual parameter does not have the col2 component (this can also be tracked in the ABAP Debugger).

CLASS class DEFINITION.


PUBLIC SECTION. TYPES: BEGIN OF
struc, col1 TYPE type1, col2
TYPE type2, END OF struc, itab
TYPE STANDARD TABLE OF struc.
METHODS: main, sort_itab
CHANGING c_itab TYPE itab.
ENDCLASS.
CLASS class IMPLEMENTATION.
METHOD main.
TYPES: BEGIN OF struc,
col1 TYPE type1,
col3 TYPE type2, END
OF struc.
DATA itab TYPE STANDARD TABLE OF struc
WITH NON-UNIQUE KEY col1 col3.
... sort_itab( CHANGING
c_itab = itab ).
ENDMETHOD.
METHOD sort_itab.
SORT c_itab BY col1 col2.

Page: 188 of 227


SORT c_itab BY ('COL1') ('COL2'). "<- Runtime error!
ENDMETHOD.
ENDCLASS.

5.5.5.3.5 Good example

The following source code shows a very simple correction of the typing in the above example. Because the
primary table key is completely specified, the used type is no longer generic, and the dynamic sorting functions
like the static sorting.

...
itab TYPE STANDARD TABLE OF struc
WITH NON-UNIQUE KEY col1 col2.
...

Internal and External Procedure Calls

5.5.6.1 Background

When a procedure is called, a distinction is made between internal and external procedure calls. An internal call
calls a procedure of the same program, whereas an external call calls a procedure of a different program. The
major difference between internal and external procedure calls is that the program might have to be loaded first
for an external call. With internal calls, the program is already loaded. Possible external calls, where a program
might have to be loaded, include:

• Methods of global classes in class pools

• Function modules in function groups

• Subroutines in all programs that can contain subroutines (PERFORM...IN PROGRAM)

• Methods of local classes, where the name of the class is specified dynamically using an absolute type
name (\PROGRAM= ... \CLASS=...\)

The programs loaded within an internal session are grouped into program groups. There is always a main
program group and possibly multiple additional program groups. Each program group contains a main program
and possibly several additional programs (loaded due to external use). The loaded programs are not always the
result of a call. The reason could also have to do with other references to components of external programs,
such as a reference to a visible data type of a global class. The loaded programs are not always the result of a
call. The reason could also have to do with other references to components of external programs, such as a
reference to a visible data type of a global class.

If shared resources of the program group are accessed in an externally called procedure, the information
about which program group the program was loaded into is very important. Whether a program creates a
separate program group when loaded or whether it is loaded into an existing program group, largely depends
on the program type:
• Class pools and function groups (and external calls of global class methods or function modules)
always create a new program group when loaded.

• If subroutines or methods of local classes of other program types (not class pools and function groups)
are called externally, the programs are loaded into the program group of the calling program.

5.5.6.2 Rule

Page: 189 of 227


Only call suitable procedures externally

Only call procedures externally that are intended for external calls. The methods of global classes and function
modules are intended for external calls. Subroutines and the methods of local classes are not designed for
external calls.

5.5.6.3 Details

The only procedures designed for external calls are the visible methods of global classes and function modules.
The master programs of these procedures are always main programs of their program groups and the
procedure always works with the resources of this program group.

However, external calls of subroutines and dynamic calls of methods in local classes of other programs are
problematic. Usually, subroutines and local classes are intended for internal use within their program. External
calls are not anticipated during the development phase. (On the other hand, no problems occur when an
already loaded program deliberately passes a reference to an object of a local class to another program).
Therefore, these subroutines and local classes should always be handled as private components of the
program, even though they are technically public.

In addition, an assignment to a particular program group is not statically defined. Because the call order can
depend on user actions or data contents, the program of the called procedure can belong to the main program
group in one instance and can belong to an additional program group in another instance. This does not define
which program group the shared resources belong to. The shared resources are:

• Classic dynpros (including selection screens and classic lists) and GUI statuses

The classic dynpros and GUI statuses are always shared within a program group (the classic dynpros
and GUI statuses of the main program in this program group). For example, the CALL SCREEN
statement in an externally called procedure always calls a dynpro of the main program of the program
group and not a dynpro of the master program of the procedure. The response to user actions in the
dynpro (called as described above) is also handled in the main program of the program group.

• Interface work areas

Interface work areas are defined as table work areas using the TABLES and NODES statements or
using the obsolete statement DATA ... COMMON PART. They are only created once for each program
group and are shared by the main program and the loaded additional programs.

5.5.6.3.1 Note

Except for the warning regarding dynamic calls of methods of local classes from other programs, this rule is
basically intended to raise the awareness of problems when using existing programs. In new programs, the
creation of new subroutines and the use of shared resources are largely obsolete anyway. The problems
mentioned above can only occur if classic dynpros or selection screens (and therefore GUI statuses and
table work areas) are used. 5.5.6.3.2 Example
The following source code demonstrates how to assign interface work areas to program groups, in the case of
external subroutine calls. The table work area dbtab declared in sapssubr is shared either with sapmprog or
with saplfugr. If share has the value 'FUGR', saplfugr and sapssubr share the table work area. Otherwise it is
shared by sapmprog and sapssubr. It is not possible to rely on a specific assignment.

***********************************
PROGRAM sapmprog.
TABLES dbtab.
...
IF share = 'FUGR'.
CALL FUNCTION 'FUNC'.

Page: 190 of 227


ENDIF.
...
PERFORM sub IN PROGRAM sapssubr.
***********************************
***********************************
FUNCTION-POOL saplfugr.
TABLES dbtab.
...
FUNCTION func.
PERFORM sub IN PROGRAM sapssubr.
ENDFUNCTION.
***********************************
***********************************
PROGRAM sapssubr.
TABLES dbtab.
...
FORM sub.
...
ENDFORM.
***********************************

Exiting Procedures

5.5.7.1 Background

You can exit procedures in the usual way using the END... statement or by using one of the following
statements:

• RETURN

• EXIT

• CHECK log_exp

These statements end a procedure properly, that is, the system passes output parameters for which passing by
value is specified and returns values to the assigned actual parameters. In addition, you can terminate the
processing of a procedure as follows, whereby the actual parameters are not supplied with values:

• Calling another unit (program, dynpro) without returning to the procedure

• Triggering an exception or sending a dialog message if an error occurs


5.5.7.2 Rule

Only use RETURN to exit procedures

Use the RETURN statement to properly exit a procedure (method, see rule no implementations in function
modules and subroutines) early.

5.5.7.3 Details

The RETURN statement serves to exit procedures and always has this result. The behavior of the EXIT and
CHECK statements (conditional exit), in contrast, is context- dependent: Within a loop, only the loop is exited;
outside a loop, the surrounding procedure is exited. This ambiguity limits the legibility of source code.

Page: 191 of 227


Therefore, EXIT and CHECK should only be used to exit loops, and RETURN only to exit procedures. Only
RETURN enables you to exit a procedure in a loop context.

5.5.7.3.1 Note

As well as the statements RETURN, EXIT, and CHECK listed here, the statements REJECT and STOP can be
used to exit special event blocks. Conversely, RETURN, EXIT, and CHECK can also exit processing blocks
other than procedures. In both cases, you must consider the particular behavior of the ABAP runtime
environment regarding the exited processing block. Because other processing blocks are only supposed to
contain one method call according to the rules use ABAP Objects and no implementations in dialog modules
and event blocks, these cases should no longer occur in new programs.

5.5.7.3.2 Exception

An exception to the rule to only use RETURN to exit procedures are CHECK statements that are located at the
beginning of a procedure and that check the prerequisites for the execution of the procedure there. Using the
CHECK statement in such a way does not impair the legibility and is thus allowed. However, this exception
does not apply to other positions within a procedure and outside loops.

5.5.7.3.3 Bad example

The following source code shows how a method is left early with a CHECK statement, whose meaning cannot
be identified by simply looking at it. You have to know that CHECK exits the procedure if the following logical
expression is wrong, which is why a double negation is necessary here.

METHOD some_method.
...
CHECK is_finished = abap_false.
...
ENDMETHOD.

5.5.7.3.4 Good example

The following source code corrects and simplifies the above example by implementing a conditional exit with an
IF control structure that is easy to read.

METHOD some_method.
...
IF is_finished = abap_true.
RETURN.
ENDIF.
...
ENDMETHOD.

Dialog Modules and Event Blocks

5.5.8.1 Background

Besides procedures, there are two further types of processing blocks. However, they do not have a parameter
interface and do not allow declaration of local data: (AT SELECTION-SCREEN and GET are exceptions but
they should not be exploited):

• Dialog Modules

Page: 192 of 227


Dialog modules are introduced using the MODULE statement and ended using the ENDMODULE
statement. These modules form the functional interface between classic dynpros and the associated
ABAP program. They are called from within the dynpro flow logic.

• Event Blocks
Event blocks are introduced by the corresponding keyword and implicitly ended by the next processing
block. The processing of an event block is triggered by the ABAP runtime environment when the
relevant event occurs. There are event blocks for:

o Loading a program (LOAD-OF-PROGRAM)

o Reporting events that occur during the processing of an executable program (with a logical

database) (INITIALIZATION, START-OF-SELECTION, GET, END-OF-SELECTION) o

Selection screen events (AT SELECTION-SCREEN ...) o List events of classic list

processing (AT LINE-SELECTION, AT USER-COMMAND)

5.5.8.2 Rule

No implementations in dialog modules and event blocks

Only use dialog modules and event routines if they are necessary from a technical viewpoint. In these cases, do
not implement the required function. Instead, call the relevant (local) methods.

5.5.8.3 Details

Since it is not possible to declare local data in dialog modules and event blocks, you cannot implement any
useful program logic. Therefore, dialog modules and event blocks # provided that they are still necessary #
should only contain one method call. If you use ABAP Objects consistently, only the following elements are
required:

• LOAD-OF-PROGRAM or INITIALIZATION as the program constructor in cases where program types


other than class pools are used

• Dialog modules and AT SELECTION-SCREEN when classic dynpros and selection screens are
processed

• START-OF-SELECTION in executable programs for background processing To improve readability,


you should always specify the statement explicitly (although it is optional in many situations).
• Although it is syntactically possible, you should never specify an event block several times within a
program.

5.5.8.3.1 Note

Using LOAD-OF-PROGRAM in a function group is basically the same as using a static constructor in a global
class. In executable programs, you can use INITIALIZATION instead, if any parameters passed using SUBMIT
need to be evaluated.

5.5.8.3.2 Example

Page: 193 of 227


The following source code shows the PAI modules of the function groupDEMO_CR_CAR_RENTAL_SCREENS
from the package SABAP_DEMOS_CAR_RENTAL_DYNPRO. The screens in this package can be called using
transaction DEMO_CR_CAR_RENTAL. These dialog modules adhere to the above rule. They do not contain
their own implementations. They call methods of a local class of the function group.

MODULE cancel INPUT.


screen_handler=>cancel( ).
ENDMODULE.
MODULE user_command_0100 INPUT.
screen_handler=>user_command_0100( ). ENDMODULE.
MODULE customers_mark INPUT.
customer_table=>mark( ).
ENDMODULE.
MODULE reservations_mark INPUT.
reservation_table=>mark( ).
ENDMODULE.

Macros

5.5.9.1 Background

A macro is a summary of a statement list for internal reuse within a program between DEFINE and END-
OFDEFINITION. The statement list is included in another position in the program by specifying the macro
name. A macro can contain up to nine placeholders, &1 to &9, in place of ABAP words and operands (or parts
of operands). These placeholders must be replaced by fixed words when the macro is included.

5.5.9.2 Rule

Only use macros in exceptional cases.

We recommend that procedures (methods) or expressions with appropriate operators are used instead of
macros.

5.5.9.3 Details

Macros are often used as callable units, instead of real procedures. This is rarely a good idea however. Macros
do not have a real context, and cannot be executed in steps in ABAP Debugger. This makes it practically
impossible to look for errors in programs that use large or complex macros. For these reasons, a macro cannot
be viewed as a worthy replacement for a genuine procedure.
In addition, in the past macros were not just used to replace procedures, they were also used to perform
recurrent declarations of structured data. Today, macros are, of course, avoided and standalone types are used
instead.

Nowadays, expressions can be used instead of macros in many cases. One example is using the value
operator VALUE to fill internal tables, which makes it unnecessary to use macros (which mostly contain the
statement APPEND.

In certain cases, however, the use of macros could be justified, as long as the statement patterns are simple
and recurring. Here, a macro can be seen as a design-time generation tool. The following (good) example
shows how a macro can be used in this way. In a situation like this, a macro may be preferable to a procedure
for the following reasons:

Page: 194 of 227


• The statement list in the macro is clear and simple enough that it does not matter that it cannot be
debugged.

• The syntax check performs static checks on the correctness of the statements. When using the
dynamic language methods required in a procedure, any errors (in this case, incorrect names) would
not be detected until runtime. Dynamic access would also be more time-consuming.

• Unlike listing all statements separately, using these macros makes the source code clearer, particularly
if the statement list is repeated frequently. There is a lower risk of trivial typing errors being made, since
there is no need to create and edit a large volume of similar source code. It is easier to make
subsequent changes to the logic.

This means that, in certain cases, using macros can improve the correctness and maintainability of source
code. Macros that contain non-trivial control structures, however, always present a maintenance problem
because they cannot run in steps in ABAP Debugger. For this reason, use macros very sparingly and only if
they contain no more than a few lines. Errors in macros are almost impossible to analyze.

5.5.9.3.1 Note

As well as existing in the source code of a program, macros can also be saved as cross-program macros in
type groups. However, no new macros should be defined in type groups.

5.5.9.3.2 Bad example

The following source code is an example where a macro is an unsuitable replacement for a genuine procedure.
In this case, the macro could only be used once and in a single context, since the work area wa can only be
declared once there. In this example, a procedure with dynamic components would be a better idea.

DEFINE get_data.
DATA wa TYPE &1.
SELECT SINGLE *
FROM &1
WHERE &2 = @&3 AND
&4 = @&5
INTO @wa.
END-OF-DEFINITION. get_data spfli
carrid 'LH' connid '0400'.

5.5.9.3.3 Good example

The following source code shows an example where using a macro could be a good idea. Here, a few simple
statement lists (assignments enclosed in IF) are to be repeated often. The names of the operands are also very
regular. This function could also be implemented using other means (such as a procedure) by using dynamic
means to access the variables or by expanding every IF block. In this particular case, however, using a small
macro makes the program far easier to understand and edit.

TYPES: BEGIN OF value_and_flag,


value TYPE string,
flag TYPE c LENGTH 1,
END OF value_and_flag.
TYPES: BEGIN OF structure,
component_up TYPE value_and_flag,
component_down TYPE value_and_flag,
...

Page: 195 of 227


component_top TYPE value_and_flag,
END OF structure.
DATA struct TYPE structure.
DEFINE macro_set_value_if_flag_is_set.
IF struct-component_&1-flag = abap_true.
struct-component_&1-value = &2.
ENDIF.
END-OF-DEFINITION.
... macro_set_value_if_flag_is_set up
'ABC'. macro_set_value_if_flag_is_set
down 'IJK'.
... macro_set_value_if_flag_is_set top
'XYZ'.
...

5.6 Dynamic Programming Techniques


Dynamic programming techniques are all techniques whose functions or effects are detectable only at runtime
of a program in the runtime environment.

Security Note

If used wrongly, dynamic programming techniques can present a serious security risk. Any dynamic content that
is passed to a program from the outside must be checked thoroughly or escaped before being used in dynamic
statements. This can be done using the system class CL_ABAP_DYN_PRG or the predefined function escape.

Using Dynamic Programming Techniques

5.6.1.1 Background

The use of dynamic programming techniques includes the following:

• Accessing dynamic memory objects, that is, dynamic data objects (strings and internal tables), as well
as instances of classes and anonymous data objects

• Dynamically accessing data objects using reference variables and field symbols (to a certain extent,
this also includes accessing generically typed formal parameters in procedures)

• Dynamically invoking procedures or entire programs


• Generically generating data types and using them to create anonymous data objects

• Generically developing programs in which parts of the statements are specified using dynamic tokens,
or entire programs are only generated at runtime

In this sense, handling reference variables can also be considered a dynamic technique. The dynamic type (the
object to which the reference refers) can be more specific than the static type of the variable, which entails
polymorphic behavior and becomes apparent during assignments in the form upcasts or downcasts.

Page: 196 of 227


5.6.1.2 Rule

Use dynamic programming techniques with care

Use dynamic programming techniques only when this is necessary and reasonable. Use only as many dynamic
language elements as required to carry out the assigned task.

5.6.1.3 Details

The advantage of dynamic programming techniques is an increased flexibility when creating programs.
Dynamic programming techniques enable flexible and generic services to be developed that meet various
requirements. The price to be paid for this advantage is that dynamic programming techniques may decrease
the static checkability, legibility, maintainability, testability, performance, and also security. Security standards
may even prohibit the use of high-risk dynamic programming techniques.

This section describes various dynamic programming techniques. These range from using strings, which we
explicitly recommend, and using internal tables, which form a basis of ABAP programming, to generating entire
programs, which we advise against. The higher the dynamics, the more comprehensive the precautionary
measures to be taken when using these techniques. Already the simple access to data objects involves a
corresponding partial aspect, which was addressed in the rule for Runtime Errors when Accessing Data
Objects. The rules in this section extend such specific rules and provide a more general framework.

Always consider the following aspects when deploying dynamic techniques:

• Programs that work with dynamic techniques are usually more complex and harder to understand than
programs that use only static techniques. This has a negative effect on maintainability.

• In dynamic programming, many checks that are otherwise performed during compilation can be
performed only at runtime. This considerably increases the risk of exceptions or runtime errors.

• Checking the dynamic parts at runtime can reduce the processing speed, as the checks must be
repeated each time the parts are used again.

• More tests are required, since numerous states of a dynamic program and possible error situations
must be checked.

• If used wrongly, dynamic programming techniques can present a serious security risk. Any dynamic
content that is passed to a program from the outside must be checked thoroughly or escaped before
being used in dynamic statements. This can be done using the system class CL_ABAP_DYN_PRG or
the predefined function escape.

The significance of these aspects differs for the various dynamic programming techniques. For example, a
program that uses strings is by no means more complex than a program that works only with text fields. In such
a case, a range of details must nevertheless be taken into account.

Runtime Errors in Dynamic Processing

5.6.2.1 Background

When dynamic techniques are used, various exception situations can arise that can never occur when the
corresponding static techniques are used because they can be checked statically.

Page: 197 of 227


5.6.2.2 Rule

Preventing Runtime Errors in Dynamic Processing

Respond appropriately to all possible error situations when using dynamic techniques.

5.6.2.3 Details

The different dynamic techniques also require different reactions to the possible exception situations. Examples:

• When dynamic data objects are accessed, their limitations must not be violated. For internal tables, for
example, no row numbers must be specified for which no row exists.

• Before data objects are accessed dynamically by using data references or field symbols, it must be
ensured, before execution, that these are bound to a data object and this binding checked using IS
BOUND or IS ASSIGNED, if necessary. Afterwards, the return value should be checked to see whether
execution was successful.

• In dynamic calls, exceptions must be caught that are raised due to nonexistent programs, classes, or
procedures, or due to inappropriate parameters.

• In the case of a dynamically specified token, for example, a dynamic WHERE condition in Open SQL
or internal tables, possible exceptions must be caught and responded to accordingly.

• If programs are developed generically, the programs in question must checked using the statement
SYNTAX-CHECK.

These examples illustrate how the use of dynamic techniques can lead to more complex and less clear code
due to the numerous possible exception situations. Of course, the more the mentioned techniques are
combined, the more complex and less clear the code becomes. Therefore, dynamic programming techniques
must always be used with care.

5.6.2.3.1 Note

If it is not possible to particular error situations, for example, because no exception that can be handled exists, it
must be ensured that this error situation never occurs and this then verified in extensive test scenarios.

5.6.2.3.2 Bad example

The seemingly legible source code section uses almost only dynamic operands and tokens. Neither the ABAP
Compiler nor the reader can know the content of the specified variables at runtime. An error in one of these
variables results in a termination of the program.

READ TABLE where_clauses ASSIGNING <where_clause> WITH ...


DELETE FROM (dbtab_name) WHERE (<where_clause>).
IF sy-subrc = 0.
CALL METHOD (class_name)=>(method_name).
ENDIF.

5.6.2.3.3 Good example

The following source code corrects the above example with an appropriate error handling — this reduces the
legibility, of course. Here, it is additionally considered that an initial dynamic WHERE condition means that no

Page: 198 of 227


restrictions are imposed. As shown here, this case must be explicitly avoided. Otherwise, the entire table
content will be deleted.

UNASSIGN <where_clause>.
ASSIGN where_clauses[ ... ] TO <where_clause>.
IF sy-subrc <> 0.
RAISE EXCEPTION ...
ENDIF.
ASSERT <where_clause> IS ASSIGNED.
IF <where_clause> IS NOT INITIAL.
TRY.
DELETE FROM (dbtab_name) WHERE (<where_clause>).
CATCH cx_sy_dynamic_osql_error.
...
ENDTRY.
IF sy-subrc = 0.
TRY.
CALL METHOD (class_name)=>(method_name).
CATCH cx_sy_dyn_call_error.
...
ENDTRY.
ENDIF. ENDIF.

Using Dynamic Data Objects

5.6.3.1 Background

Dynamic data objects are a subgroup of dynamic memory objects and simply consist of:

• Strings

• Internal tables

The data type statically defines all properties for dynamic data objects, apart from memory consumption.
Although the objects are managed internally using references, they are addressed by their names and value
semantics applies. This means the referenced internal reference is always used for access.

5.6.3.2 Rule

Use appropriate dynamic data objects

To store dynamic data sets transiently when using dynamic data objects, always select the type that best
corresponds to the content and the required access:

• Strings for data that cannot be divided

Page: 199 of 227


Internal tables for data that can be divided

To avoid memory bottlenecks for large data sets, you might need to use other procedures as well.

5.6.3.3 Details

When using dynamic data objects, selecting the type is a key decision. The general rule is:

• Data that can be handled as one piece is stored as a character string or byte string (string or xstring
data type).

• Structured data or data that can be sensibly divided into individual sections is stored as internal table
rows.

However, if you need to store a very large data set as dynamic data objects, different aspects must be
considered. String and xstring data objects must be stored as one piece in the memory, whereas the content of
internal tables is stored in blocks. This is more likely to cause resource bottlenecks when strings are used. Even
if sufficient memory space is available, the memory cannot handle a string of the requested length, due to
fragmentation. In these cases, it makes more sense to store the data as an internal table instead of storing the
data in a string as one piece.

The EXPORT statement for storing data in a cluster supports both storage types, for example: EXPORT ... TO
DATA BUFFER stores the cluster in a single long byte string, whereas EXPORT ... TO INTERNAL TABLE
distributes the cluster across numerous rows of an internal table. The latter possibility (EXPORT ... TO
INTERNAL TABLE) is more secure (for the reason explained above), if the cluster needs to contain a very large
data set.

5.6.3.3.1 Note

Strings and internal tables are predefined in the ABAP language as data types and the corresponding access
statements. In other programming languages, however, they are often implemented as libraries (such as string
classes and container classes). In ABAP, it is usually neither necessary nor useful to define specific classes for
storing strings or table-like data. However, in rare cases, it may be useful to wrap internal tables in classes, to
release more memory when data is deleted.

Memory Consumption of Dynamic Memory Objects

5.6.4.1 Background

In dynamic objects, the actual data is addressed using a reference. This means that dynamic memory objects
are always deep objects. Possible dynamic memory objects are:

• Table bodies of internal tables addressed using internal table references

• Text strings or byte strings addressed using internal string references

• Anonymous data objects created using CREATE DATA and addressed using data references in data
reference variables

Page: 200 of 227


• Instances of classes created using CREATE OBJECT and addressed using object references in object
reference variables
The maximum total size and number of all dynamically managed memory objects in an internal session are
defined in principle by the maximum amount of memory that this session can request to execute programs.

Alongside the available memory on the application server, there are two further technical limits that can restrict
the size of individual dynamic memory objects:

• The upper limit is 231-1 for the size of a string in bytes (in a Unicode system, every character in a
string occupies 2 bytes) and the number of rows in an internal table.

• The memory for the content of a string and for hash management of an internal hashed table must be
provided as one piece. Therefore, the ztta/max_ memreq_mb profile parameter is relevant for these
two memory object types. It defines the maximum amount of memory that can be requested as one
piece. A maximum size for strings and a limitation on the number of rows in hashed tables can be
directly derived from this amount. This limitation does not depend on the width of table rows. Only the
hash management (and not the table content) must be provided as one piece in the memory. The
current limitation is the highest power of two, which is less than or equal to an eighth of the value
specified by the profile parameter. For example, if the profile parameter specifies 250MB, a hashed
table can contain approximately 16 million rows.

Any attempt to exceed these limits results in a runtime error and the termination of the program.

5.6.4.2 Rule

Avoid memory bottlenecks

When using dynamic memory objects, ensure that the program is not terminated due to a lack of memory.

5.6.4.3 Details

Memory limits are fixed limitations that cannot be deactivated with programming. To avoid memory bottlenecks,
we recommend that you account for:

• The limits of the available physical memory when developing a program

• The specified technical limits for strings and hashed tables

The only way to prevent memory limits from being exceeded is to use programming to restrict the data loaded
into the memory. This applies to processing large data sets and also to object creation. The latter can result in
memory bottlenecks, if overly large objects or too many small objects are created. Memory leaks (unused,
unreleased memory) can also cause memory problems.

Editing Large Data Sets


You need to process large data sets that are stored in a persistent storage as one piece, but the sets do not fit
into the available memory. In this case, you must import and process these data sets, either in packages or
sequentially. A common language element here is the PACKAGE SIZE addition. You can this addition when
importing large data sets to internal tables with the SELECT Open SQL statement. Memory-saving processing
of large strings (Large Object, LOB) in database tables is also possible. Locators enable you to access
substrings of strings in database tables. Streaming allows a sequential and gradual transfer of data into the
memory. Both concepts were predominantly introduced in ABAP to avoid memory bottlenecks.

Releasing Memory

Page: 201 of 227


The main advantage of dynamically managed memory is that it can be released again. Use this option to delete
data and objects no longer required, to avoid memory leaks and possible memory bottlenecks:

• You can delete strings using the CLEAR statement.


You can use CLEAR or FREE to delete internal tables. FREE releases the entire memory space
occupied by rows, whereas the initial memory requirement of the table remains reserved if CLEAR is
used. An appropriate size for the initial memory requirement is usually defined by the ABAP runtime
environment itself. However, it can also be predefined using the INITIAL SIZE addition.

• Anonymous data objects and instances of classes are deleted by the Garbage Collector, after all
reference variables that refer to these objects have been initialized. Here, you must ensure that all
references are actually identified during initialization. This is not always straightforward, particularly in
the case of complex object networks. To analyze memory problems and detect memory leaks, you can
use Memory Inspector and the ABAP Debugger memory analysis. You can display memory
consumption rankings for all dynamically managed memory objects.

5.6.4.3.1 Note

Note that statically managed data objects can also involve unnecessary memory consumption. For example,
large flat structures with unused or initial components, whose initial values require a lot of memory space.
Character strings that only contain spaces are particularly significant in Unicode systems with 2 bytes for each
space. The situation can become particularly critical if these structures are combined with dynamic techniques
(if they are used as internal table rows, for example). Consequently, boxed components were introduced. They
support initial value sharing for initial substructures, which means that the initial value of a substructure is
created only once in memory. For structures with substructures that have a sparse fill level, this can reduce
memory consumption and copy costs significantly.

5.6.4.3.2 Bad example

In the following source code, all the data in a very large database table is imported into an internal table. Here
there is an obvious risk of memory bottlenecks.

SELECT *
FROM very_large_table
INTO TABLE ...

5.6.4.3.3 Good example

In the following source code, the PACKAGE SIZE addition is used. This restricts the maximum size of the
internal table to a secure level.

SELECT *
FROM very_large_table
INTO TABLE ... PACKAGE SIZE 1000.
ENDSELECT.

Administration Costs of Dynamic Memory Objects

5.6.5.1 Background

Dynamic memory objects provide flexibility, but this comes at a price. The administration of these objects incurs
internal costs, which are reflected in increased memory consumption, and in the worst case possibly far too
high.

Page: 202 of 227


The total memory requirements of a dynamic memory object comprise the requirements of the objects
themselves and the requirements of the administration data. The administration data consists of the reference,
with a fixed size of 8 bytes, and a header that contains the address of the data itself and additional
administration information. The reference initially points to a header and not directly to the object. The size of
the header is itself dynamic and depends on the category of memory object as follows:

Page: 203 of 227


String headers of strings whose length is less than approximately 30 characters or 60 bytes require
between 10 and 40 bytes approximately, depending on the string length. For longer strings, the header
requires approximately 50 bytes, regardless of the string length.

• Table headers require approximately 150 bytes (in 32 bit architecture) or approximately 200 bytes (in
64 bit architecture).

• Object headers of anonymous data objects and instances of classes require approximately 30 bytes,
regardless of the object.

The headers are created when dynamic data objects are provided with content or when objects are generated.
When a dynamic data object (a string or internal table) is initialized, only the content itself is deleted, while the
header is retained to be used again. Only the statement FREE deletes (some) table headers that are too big.
When it deletes an object, Garbage Collector also deletes the object header.

Accessing Data Objects Dynamically

5.6.6.1 Background

Field symbols and data references are used to access data objects whose name and attributes are not known
until runtime.

• Field symbols
A field symbol is a symbolic name for a data object declared with FIELD-SYMBOLS, to which
memory areas can be assigned using the ASSIGN statement or, if internal tables are processed, using
the ASSIGNING addition. Field symbols are typed either generically or completely and can be used like
a data object in all appropriate operand positions. For typing, the same rules apply as for formal
parameters of procedures. When accessing field symbols, value semantics applies, which means that
the assigned memory content is addressed directly. Field symbols are thus always handled like
dereferenced pointers.

• Data references
A data reference is the content of a data reference variable that is declared using REF TO and
points to any data objects or parts of data objects. Data references are needed to create anonymous
data objects using CREATE DATA or NEW. They can also be generated for existing data objects,
however, using the statement GET REFERENCE, the reference operator REF, or, if internal tables are
processed, using the REFERENCE INTO addition. A data reference variable is either completely
generic or completely typed. When accessing data reference variables, reference semantics applies,
which means that the data reference itself is addressed. To access the referenced memory content, a
data reference variable must be dereferenced explicitly using the dereferencing operator (->*).

Field symbols and data references are closely linked because only completely typed data reference variables
can be dereferenced in any operand position. Completely generic data reference variables (REF TO data) can
be dereferenced in the ASSIGN statement only.

Data reference variables can be declared in the same context as all other data objects, especially also as
attributes of classes. Field symbols, in contrast, can only be declared within procedures (methods) or in the
global declaration section. However, the latter is no longer allowed.

5.6.6.2 Rule

Use field symbols and data references in appropriate ways

Page: 204 of 227


Use field symbols and data references for the purpose that best matches their semantics:
Field symbols for value access (value semantics)

• Data references for working with the references (reference semantics)

5.6.6.3 Details

Both field symbols and data references can be understood as pointers to memory areas. The main difference is
in the different access semantics.

• Due to their value semantics, field symbols should always be used if the focus is on the access to
referenced data. Field symbols provide specific functions for this purpose, which are not available for
data references:

o Dynamic access to attributes of classes and objects


ASSIGN (class_name)=>(attr_name) ... ASSIGN oref-
>(attr_name) ...

o Dynamic access to structure components ASSIGN ...


COMPONENT ...

o Explicit casting
ASSIGN ... CASTING ...

o Dereferencing of generic data reference variables


ASSIGN dref->* ...

• Due to their reference semantics, data references are to be used if the focus is on the explicit handling
of references to data objects. Data references are vital for the generation of anonymous data objects or
complex dynamic data structures, such as trees or chained lists in the internal session or in the shared
objects memory. Furthermore, data references are the preferred element for implementing explicit
sharing between any data objects, and for passing pointers to data objects to procedures.

5.6.6.3.1 Note

Actually, data reference variables can be better used in programs that are based on ABAP Objects because
they have the same semantics as object reference variables and therefore represent a more modern
programming concept. Field symbols, on the other hand, provide more functions than data references and can
thus not always be replaced by them. Consequently, the usage of field symbols for dynamic accesses to data
objects is still recommended, although the sole use of data references would be preferred for consistency and
simplicity reasons.

5.6.6.3.2 Bad example

The following source code shows a loop for an internal table in which the system is supposed to directly access
the current row. If a generic data reference variable is used for this purpose, a field symbol is also needed for
its dereferencing.

METHOD some_method.
"IMPORTING i_itab TYPE INDEX TABLE
DATA dref TYPE REF TO data.
FIELD-SYMBOLS <fs> TYPE data.
...
LOOP AT i_itab REFERENCE INTO dref.

Page: 205 of 227


ASSIGN dref->* TO <fs>.


<fs> = ...
ENDLOOP. ...
ENDMETHOD.

5.6.6.3.3 Good example

The following source code simplifies the above example by using a field symbol, which is required to access
table rows anyway, directly and without using a data reference. The direct use of the field symbol thus also
complies with the KISS principle.

METHOD some_method.
"IMPORTING i_itab TYPE INDEX TABLE FIELD-
SYMBOLS <fs> TYPE data.
...
LOOP AT i_itab ASSIGNING <fs>.
<fs> = ...
ENDLOOP.
...
ENDMETHOD.

Generic Programming

5.6.7.1 Background

Generic programming (dynamic creation of source code) makes programs as dynamic as possible. The
following methods can be used to achieve this:

• Dynamic token specification


Dynamic token specification involves specifying individual operands or whole parts of statements
(clauses) in the form of character-like data objects. These are usually enclosed in parentheses and
must contain source code with correct syntax at runtime. Important examples: o Dynamic access to

attributes of classes (Dynamic Access) o Call procedures dynamically, especially methods

(Dynamic Invoke)

o Dynamic type specifications when anonymous data objects are created. In this case, types can be
used that are only created at runtime using Runtime Type Services (RTTS).

o Dynamic specifications of clauses when internal tables are accessed or in Open SQL.
Dynamic token specifications are often used in combination with dynamic access to data objects.

• Program generation
Program generation involves preparing complete programs as content for internal tables and then
creating the programs. A distinction is made between the following cases:

• Transient program generation using GENERATE SUBROUTINE POOL, where the generated
programs only exist in the internal session of the current program.

• Persistent program generation with INSERT REPORT. The generated programs are saved as
repository objects.

Page: 206 of 227


5.6.7.2 Rule

Avoiding Program Generation

Page: 207 of 227


Program generation should only be used as a last resort for generic programming. Other dynamic methods
(especially in application programs) should be tried first, such as dynamic token specification, runtime type
services (RTTS) and dynamic access to data objects.

5.6.7.3 Details

Program generation has a lot of conceptual problems such as checking, testing, and editing the new programs.
In addition, programs generated hastily can be a security risk because they cannot be statically checked.
Generating programs is usually very intensive in terms of runtime and resources. Due to the above reasons,
program generation should be avoided wherever possible and other dynamic methods used instead:

• The dynamic token specification has the advantage that only parts of the statements are dynamic. The
rest can be checked statically.

• Runtime type services (RTTS) can be used as follows:

o RTTS define the type properties of data objects at runtime (Runtime Type Information, RTTI). The
capabilities of RTTI extend far beyond the statement DESCRIBE FIELD.

o It creates types at runtime (Runtime Type Creation, RTTC). RTTC should be used if the CREATE
DATA statement does not offer sufficient options for the planned implementation (for example,
building new structures).

These methods, combined with field symbols and data references, are now usually sufficient for most tasks that
could only be solved using program generation in older releases.

5.6.7.3.1 Exception

Program generation should only be used as a last resort if the other methods are not sufficient to achieve
dynamic program control. Another reason is the processing speed. When program generation is used, the costs
incurred due to checking and generation occur less frequently than with the other dynamic methods. However,
program generation is usually associated with worse system performance than dynamic token specification. The
conceptual problems explained at the start are still applicable here and therefore careful consideration is
needed.

Unlike application programs, system programs usually frequently rely on program generation and the associated
language constructs. Examples include the generation of proxy classes for Web Dynpro or Web Services. ABAP
Editor also uses statements such as READ REPORT and INSERT REPORT.

5.6.7.3.2 Note

Even generated programs should always adhere to the predefined guidelines. For example, the program logic
should be implemented/generated in a generated subroutine pool in the form of local classes. The generated
functions are usually called by means of a single subroutine that is used as an entry point into the generated
local classes (see the following example).

To minimize the risks involved, it can be useful to save syntactically correct templates that adhere to the
guidelines in the repository. READ REPORT can then be used to load the templates as templates for
dynamically generated programs, in which only small parts are changed or added at runtime.

Subroutines in generated subroutine pools are an exception to the rule, which states that subroutines should no
longer be created, and an exception to the rule, which states that subroutines should no longer be called. In
addition, absolute type names can be used to access the local classes of a generated subroutine pool. However,
this violates the rule Only call suitable procedures externally.

Page: 208 of 227


5.6.7.3.3 Bad example

The following source code demonstrates unnecessary program generation. The only reason for generating the
program is dynamic read access to a database table. The name of the database table and the row type of the
internal table (into which data is read) are replaced by a parameter value in the source code of the program to
be generated. The value operator VALUE is used to create the internal table. As recommended, the subroutine
of the generated subroutine pool only contains the call for a method of a local class where the actual
implementation is located. Instead of filling the program table row by row, it would have also been possible in this
case to create a corresponding program in the repository and load this program using READ REPORT.

PARAMETERS dbtab TYPE c LENGTH 16.


DATA table TYPE REF TO data.
FIELD-SYMBOLS <table> TYPE STANDARD TABLE.
DATA: source TYPE TABLE OF string,
program TYPE string,
mess TYPE string.
source = VALUE #(
( `program.` )
( `class main definition.` )
( ` public section.` )
( ` class-data` )
(` dyn_table type standard table of dyn_name.` )
( ` class-methods meth` )
(` exporting table type ref to data.` )
( `endclass.` )
( `class main implementation.` )
( ` method meth.` )
( ` select *` )
(` from dyn_name` )
(` into table @dyn_table.` )
( ` get reference of dyn_table into table.` )
( ` endmethod.` )
( `endclass.` )
( `form subr changing table type ref to data.` )
( ` main=>meth(` )
( ` importing table = table ).` )
( `endform.` ) ).
REPLACE ALL OCCURRENCES OF 'dyn_name'
IN TABLE source WITH dbtab.
GENERATE SUBROUTINE POOL source NAME program MESSAGE mess.
IF sy-subrc = 0.
PERFORM subr IN PROGRAM (program) CHANGING table.
IF table IS BOUND.
ASSIGN table->* TO <table>.
ENDIF.
ELSE.
...
ENDIF.

5.6.7.3.4 Good example

The following source code produces the same result as the example above, when executed successfully. In
other words, the field symbol <table> points to an internal table that is filled with data from the dynamically
specified database table. However, this task is performed much more efficiently in the example below due to the
generation of an anonymous data object and a dynamic token-specification. If the target table cannot be
structured in exactly the same way as the database table, Runtime Type Creation (RTTC) must also be used.

Page: 209 of 227


PARAMETERS dbtab TYPE c LENGTH 20.
DATA table TYPE REF TO data.
FIELD-SYMBOLS <table> TYPE STANDARD TABLE.
TRY.
CREATE DATA table TYPE TABLE OF (dbtab).
ASSIGN table->* TO <table>.
SELECT *
FROM (dbtab)
INTO TABLE @<table>.
CATCH cx_sy_create_data_error cx_sy_dynamic_osql_error.
...
ENDTRY.

5.7 Internationalization
Business software used by internationally operating enterprises has to meet certain localization requirements, for
example by providing different logon languages or by meeting different legal requirements. In the SAP
environment, the language aspect is known as internationalization and is part of the Globalization product
standard. As a consequence, translatable text sources must be used when developing in ABAP, and the
technical requirements for handling variable character sets must be respected.

Storing System Texts

5.7.1.1 Background

In ABAP programs, texts are used as parts of processed data but also as a means to communicate with the user.
The latter are called system texts, which are delivered with an ABAP application. The ABAP Workbench
manages system texts in such a way that they can be translated from the original language into other languages
independently of the actual development object. The following are examples of translatable system texts:

• Texts and documentation of data elements in the ABAP Dictionary

• Short texts and documentation of the components of local classes

• UI texts of dynpros, in Web Dynpro applications and in menu entries

• Message texts

• Text pools of ABAP programs that include the text elements of the program, for example, text symbols

• Texts of the Online Text Repository (OTR)

In addition to translatable system texts, an ABAP program can also contain untranslatable texts. These are
usually the character literals and the comments that are stored as a part of the source code.

5.7.1.2 Rule

Send only translatable system texts to the user

Specify all texts that a program uses to communicate with the user as translatable system texts. When
translatable system texts are created, there must be enough space for translations.

Page: 210 of 227


5.7.1.3 Details

This rule is not only critical when programs are used in an international environment; it applies when working in
multilingual development groups too. The prohibition of the use of character literals in the ABAP source code for
all texts that are relevant for user dialogs is derived from this rule. Character literals cannot be translated. Their
content is independent of the respective logon language. Instead of character literals, text symbols should be
used or character literals associated with text symbols. This is also checked in the extended program check.

When system texts are created, there must be enough space. It is not usually possible to change the text length
during translation, so the translator relies on there being sufficient space for a reasonable translation defined at
the development stage. This aspect is very important for longer texts, particularly if the original language is
English, because facts can normally be expressed in fewer words in English than in other languages. The
opposite can be true for short texts, for example, “Feld” (German) and “field” (English), or for compound words
that are written as two or more words in English.

5.7.1.3.1 Exception

For purely technical texts (such as HTML tags or regular expressions) that are not to be translated, character
literals or literal content of character string templates can be used. These should be marked as not relevant for
translation for the extended program check using pragmas.

5.7.1.3.2 Good example

The following source code shows how to handle translation-relevant and non-translation-relevant text elements
in source code: Technical texts that are not relevant for translation are specified as character literals. Other texts
are associated with a text symbol. If the additions of the CONCATENATE statement do not play any role (for
example, SEPARATED BY), it is preferable to use the chaining operator &&, as shown here, since this makes
the source code clearer.

html_line = '<title>' && 'Some Title'(ttl) && '</title>'.


APPEND html_line TO html_body.
...

Translation-Friendly Message Texts

5.7.2.1 Background

Message texts are translatable system texts. You can use placeholders in the short and long texts of messages.
Placeholders in short texts can either be defined uniquely in the form &i, where i can be a number between 1
and 4, or anonymously with &.

When the message is output with the MESSAGE statement, you can use the WITH dobj1 ... dobj4 addition,
which replaces the placeholders &1 to &4 and & of the short text with the content of data objects dobj1, ..., and
dobj4. The content of the first data object replaces the placeholder &1 and the first &, the content of the second
replaces &2 and the second &, and so on. In addition, the content of the data objects dobj1, ..., dobj4 is assigned
in order to the system fields sy-msgv1 to symsgv4.

5.7.2.2 Rule

Do not use anonymous placeholders (&) in message texts

Create placeholders in message texts with the unique names &1, &2, &3, and &4 only.
5.7.2.3 Details

Page: 211 of 227


As the syntax in the various languages differs, a translator may need to change the sequence of the replacement
texts when translating message texts. However, the translator can adapt the sequence of replacement texts only
if the different placeholders in a message text each have unique names. In messages with multiple placeholders,
you should therefore work with the numbered placeholders &1, &2, &3, and &4, instead of using the anonymous
placeholder (&).

5.7.2.3.1 Note

The same applies to all other constructs in which such placeholders are possible, for example, GUI titles
of classical dynpros. In cases where text in text symbols is explicitly replaced by self-defined placeholders,
the placeholders in the text symbol must have unique names and must be clearly identifiable for
translators as placeholders that are not supposed to be translated. 5.7.2.3.2 Bad example

A bad example of a message text might look as follows:

"In Tabelle & wurde der Eintrag & nicht gefunden"

If this message text was translated to

"In table & the entry & was not found"

this would not cause any problems.

If this message text was translated to The entry & was not found in table & a

MESSAGE statement when logged on in English would produce an incorrect text.

5.7.2.3.3 Good example

The following message text corrects the bad example:

In Tabelle &1 wurde der Eintrag &2 nicht gefunden

For both translations,

In table &1 the entry &2 was not found

and

The entry &2 was not found in table &1 a MESSAGE statement when logged

on in English would produce a correct text.

Text Environment

5.7.3.1 Background

The text environment is part of the runtime environment of an ABAP program and is made up of a language, a
locale and a system code page. All programs in an internal session have a common text environment.

As a default, the text environment of an internal session is determined by the logon language and can be set
programmatically by the statement SET LOCALE. The language of the current text environment is contained in
the system field sy-langu.

Page: 212 of 227


5.7.3.2 Rule

If possible, do not switch the text environment within the code

Set the statement SET LOCALE in exceptional cases only, and reverse any text environment switches in good
time.

5.7.3.3 Details

ABAP-coded services usually expect the text environment to be specified by the current user's logon language.
The services are not designed to handle text environment switches of internal sessions within the coding.

If the text environment has to be switched for a specific service due to the following exceptions, this must be
done only temporarily. This means that a switched text environment must be reset within the same program
context to prevent unexpected behavior in other programs within the same internal session.

5.7.3.3.1 Exception

Switching the text environment within the code may be necessary in the following cases:

• For processing texts that were not authored in the logon language, for example when sorting with
SORT ... AS TEXT, or when updating characters with TRANSLATE or an equivalent predefined function

• For accessing external files

5.7.3.3.2 Bad example

The following source code shows a text environment switch within a method, where the text environment is not
reset before exiting the method. This poses the danger of continuing within the wrong text environment after
returning from the method.

METHOD ...
SET LOCALE LANGUAGE ...
...
ENDMETHOD.

5.7.3.3.3 Good example

The following source code shows a text environment switch within a method, where the text environment is reset
to its original state before exiting the method.

METHOD ...
DATA env_lang TYPE tcp0c-langu.
GET LOCALE LANGUAGE env_lang.
SET LOCALE LANGUAGE ...
...
SET LOCALE LANGUAGE env_lang.
ENDMETHOD.

Character Set in Source Code

5.7.4.1 Background

Page: 213 of 227


ABAP source code is edited in the ABAP Editor tool in ABAP Workbench, itself an ABAP program. ABAP Editor
saves and processes the ABAP source code internally in a data object (an internal table).

This means that the developer edits the source code in the current text environment, and the associated code
page is used.

5.7.4.2 Rule

Use only 7-bit ASCII characters in source code

Use only characters from the 7-bit ASCII character set in ABAP source code. This avoids problems in systems
with different code pages.

5.7.4.3 Details

The 7 bit ASCII character set contains only characters that also exist in all other code pages. Restricting the
characters used in source code to this character set guarantees that this code can be edited and executed
regardless of the logon language. Source code that contains characters from other character sets could, in the
worst case, have incorrect syntax in a system with a different code page.

ABAP words in ABAP statements use only 7-bit ASCII characters anyway, which means that this rules to names,
literals, and comments.

5.7.4.3.1 Note

Unicode programs are the only possible programs, so the rule above is fulfilled automatically for names. No
appropriate syntax checks are made in obsolete non-Unicode programs. Comments are supposed to be written
in English anyway, which removes the need for any country-specific special characters.

In a Unicode system, all source code is stored in Unicode and this is why this problem does not occur there. If a
guarantee could be given that a program was written only for Unicode systems, then the rule above would at
least not be needed for literals and comments. It is not possible to ensure that a program is not used in any
nonUnicode systems, which is why general robustness rules should always be followed. This ensures that
programs can be transported from Unicode systems to non-Unicode systems without conversion losses.

Splitting Texts

5.7.5.1 Background

Usually the characters in a character string are displayed in a code page using a fixed number of bytes. This
means that it is always known in the memory where a character begins and ends. However, in some code
pages, a character can be formed from a combination of several separately saved characters.

• This is done using the combined characters of some non-Unicode code pages in non-Unicode systems,
where a string of characters produces a grapheme (the smallest unit of a writing system in a specific
language).

• This also applies to the characters of the surrogate area of the Unicode character set, that are
collectively represented in the Unicode character display UTF-16 by two consecutive 16-bit replacement
codes (Surrogate). The surrogate area, for example, includes several Chinese characters that are
predominantly used in Hong Kong. The ABAP programming area does not support this area. ABAP

Page: 214 of 227


supports the subset of UTF-16 covered by UCS-2, in which each character occupies two bytes. One
character in the surrogate area occupies four bytes and is handled as two characters by ABAP.

5.7.5.2 Rule

Only cut texts between characters

Make sure that statements do not cut character strings in any places with composite characters or surrogates.

5.7.5.3 Details

Operations that cut character strings include:

• Subfield accesses with offsets/lengths or substring functions

• The SPLIT statement

• Every assignment to a character-like field that is too short, where one side of the original value is cut off

If texts containing combined characters or surrogates are cut, this can result in undefined characters that cannot
be displayed. If there is a risk of this occurring, you can define a suitable separation position by using the
method SPLIT_STRING_AT_POSITION of classCL_SCP_LINEBREAK_UTIL.

Code Pages for Files

5.7.6.1 Background

When you open text files on the application server using the OPEN DATASET statement, you specify the
following options that are very important for internationalization:

• The ENCODING addition specifies the character representation where the content of the file is handled.

• The WITH BYTE-ORDER MARK addition, which is only possible for UTF-8 files, specifies that a byte
order mark (BOM) is inserted at the beginning of a text file when it is written.
If the code page is not specified explicitly when a file is written, it is set implicitly (to UTF-8 in a Unicode system).
If nothing is specified, a BOM is not set.

5.7.6.2 Rule

Write text files in UTF-8 and with a byte order mark.

Open text files for output explicitly in the UTF-8 code page. The byte order mark should be inserted and taken
into account when the file is read.

5.7.6.3 Details

When a file is read, the code page used is usually very difficult to identify. However, if the byte-order mark is
inserted, a file is clearly defined as a UTF-8. Therefore, you should always specify the ENCODING UTF-8 WITH
BYTE-ORDER MARK additions when opening a text output file with the OPEN DATASET statement. When a

Page: 215 of 227


text file of this type is read, it should only be opened with the SKIPPING BYTE-ORDER MARK addition, so that
the byte order mark is automatically skipped and does not appear in the read application data.

5.7.6.3.1 Exception

Files used for data exchange with applications that do not support UTF-8 format must be output in a suitable
code page.

5.7.6.3.2 Bad example

The following source code shows how a text file is opened for write access without explicitly specifying the code
page. In Unicode systems, UTF-8 is selected implicitly, but a byte order mark is not inserted.

OPEN DATASET dset FOR


OUTPUT IN TEXT MODE
ENCODING DEFAULT.

5.7.6.3.3 Good example

The following source code shows how a text file is opened for write access by explicitly specifying the UTF-8
codepage and using the byte order mark.

OPEN DATASET dset


FOR OUTPUT IN TEXT MODE
ENCODING UTF-8 WITH BYTE-ORDER MARK.

6 SECURITY
6.1 Security Principles
This section describes several common sense best practices to follow during design and development.

Document implicit security assumptions


Many security defects arise because developers make implicit assumptions about security. Examples are
Someone else has already validated this input or The user can't change this value or Only the administrator can
access this page. Developers must write down all implicit assumptions about the security of their functions /
solution. This will help the developer or other members of the team to have second thoughts, if their
assumptions are really correct. It will also make security testing much more efficient, because testers can
specifically check those assumptions. Writing down your implicit assumptions, if you don't comply with any of the
other requirements in this specification. E.g. if you do not perform output encoding in a certain context, you have
to explicitly write down why you think that this is not necessary in the specific case.

Follow the principle defense in depth


It is a security best practice to have several lines of defense in place. Banks are a good example.
They have camera surveillance, guards and alarm systems. And still they keep their money in a protected vault
with reinforced doors and complex lock.
If there are instances where you process input that must meet certain requirements, always check those
requirements close to the point where you process this input. Do not rely on previous / calling functions that
supposedly validated this input. Even if the precious functions already validated the input, an attacker may find a
way to bypass them. If you process important input, make sure you validate it before you use it.
If you write an administrative module, you will want to protect access to it with a login page as the first line of
defense. A second line of defense would be to restrict access to this module to certain

Page: 216 of 227


IP addresses. A third line of defense might be to restrict access to only a few hours of the day. A fourth line of
defense could be to keep this module (URL) secret, so attackers will have to find it first. Each line of defense
makes an attack more difficult. And if of line of defense fails, the others will still protect your asset.

Do not trust the client - there is no client-side security


Do not trust any data coming from the client machine when writing client server solutions. Attackers are very
skilled. They are able to run modified clients that behave entirely different from the standard clients users are
expected to work with. Such modified clients could skip validation functions. They could make disabled fields
editable and disabled or invisible buttons clickable. They could also modify selection lists or hidden fields in a
Web page. They could bypass attempts to block access to the HTML source of a Web page. Therefore all input
coming from a client must be treated as hostile and be thoroughly validated. For Web browsers, this includes all
form data, the browser signature, referring page, cookies and any other HTTP header information.

Write your code with an attacker's mindset


The primary goal of a developer is to make things work. Functions are written according to specifications and,
when finished, tested against these specifications. One part of this process is error handling. When handling
error conditions, people tend to assume that the users providing a certain input accidentally mistyped part of the
input. E.g.: A wrong character in the password, a letter in a numeric field or a missing @ character in an e-mail
address field. While this is true for all good users, it is not enough for malicious users. Malicious users
intentionally feed malformed input with the goal of forcing error conditions. This can be overlong input, special
characters that induce side effects or simply no input.
When writing code, always assume that attackers will try to trick your functionality into behaving unexpectedly:
• They will try to make your code crash.
• They will try to bypass your filters.
• They will try to outsmart you.
Therefore, when you write code, always switch to the attacker's perspective and ask yourself questions like:
• How can I bypass my validation function?
• How can I trick my function into revealing internal data (in error messages)?
• How can I crash my code?
• How can I corrupt my business logic?
• How can I skip a step in my multi-step process?
Do not let an attacker outsmart you. Outsmart the attacker!

Do not write your own cryptographic functions


Cryptography is an area where many mistakes are made. Writing cryptographic functions is a very complex art
that requires cryptographic expert know-how. This is definitely not something that every developer should do on
his own.
When using cryptography, always use a proven standard algorithm that is commonly regarded as best practice.
Never write custom cryptographic functions. Since all cryptographic functionality is part of security assessments,
always document the use of cryptography.
Document all instances, where cryptographic functionality is used. Document the algorithms and how you store
the keys. Also document the corresponding instances where encrypted data is decrypted again, where
applicable.

6.2 Secure Programming


Input Validation
This section describes best practices regarding input validation. The focus of input validation is to assure data
quality for all further processing of input. High data quality is a very good means to prevent attacks based on
unexpected input. Input validation in itself does not prevent all attacks.
Still, input validation is a very important first line of defense.
The requirements in this chapter should be applied to all input that is coming from a user or any other external
component.

Page: 217 of 227


6.2.1.1 Identify and document all input
Most attacks are based on malicious input. Validating this input is a crucial countermeasure. In order to validate
all input, it is important to first identify all input.
Input in this context is all variable data that is processed. This can be text from a user interface, contents of a
_le, data from a database, data returned by a remote function call. As a general rule, input should not be trusted.
No matter its source.
Therefore, you should be list that determines:
• the page / function that reads the input
• the name of the input field/variable
• the source of input (e.g. HTTP, DB, File, RFC call, etc)
• the data type

6.2.1.1.1 Example
Page Variable Data Source Type Value restrictions
Login.jsp Username HRRP Alphanumeric Max length 8
Bills.jsp accountNo DB Digits No value below 1000
Upload.jsp _ledata HTTP Binary

6.2.1.2 Validate all input


Once all input has been identified and documented, it is important to validate this input at the code level. The
following should be considered when validating input:
• check if input is empty
• check input length exceeds expected limits
• check if input is of correct type (e.g. number, date, ZIP code, etc)
• for input of type text, define a list of allowed characters and validate your input against this list
• for input with a specific format (e.g. numbers, dates, etc) check if the value is within an expected range
6.2.1.2.1 Examples
• when you expect numbers make sure the input contains only digits
• when you expect a date, don't process input of more than 12 characters length
• when you expect a date, make sure the input complies with the date format defined by the specification
• when you expect a date, make sure the date value makes sense in your business context

6.2.1.3 Use white list filters when possible


A white list filter is a filter that defines a set of allowed input values. Only allowed input is processed.
A black list filter is a filter that defines a set of disallowed input values. Only disallowed input is blocked.
The disadvantage of a black list is that if you forget a single bad pattern, your filter can be bypassed.
Therefore, whenever it is feasible to define a white list filter, use a white list filter.

6.2.1.4 Document your white and black list filters


There are cases in which white list filters result in tremendous work. For example: Allowed characters in a name
or free text field.
When you reach the conclusion that you can't validate a given input with a white list filter and have to fall back to
a black list filter, this must be documented. Insufficient black list filters are one of the key reasons why hackers
can inject bad input.
Document all usage of white and black list filters in your code. Especially black list filters should be made
configurable, so that emergency adjustments can be done immediately by the administrators.

6.2.1.5 Use data indirection


OWASP: A4 - Insecure Direct Object Reference
In input validation we quickly learn that validating simple data formats that adhere to a strict structure (e.g.
numbers and dates) is far easier than validating textual input. Therefore, you should always try to avoid textual
input.

Page: 218 of 227


Instead of a string, try to accept only a number that represents an index pointer to a list of allowed strings known
to your applications. If you relate to data indirectly you can avoid a lot of textual input validation and thereby
reduce your attack surface.
For example: Whenever the user is presented with a textual list of choices, you should use an ID as data
indirection. When a user is to pick a country from a list of countries, don't use the name of the country as input
but an index that points to this name. This way, complex textual input validation (probably involving black list
filters) can be reduced to validating numbers.
This makes sense for all textual choices that are hard coded. In cases where the actual list of values is stored in
a database or in a folder on a hard disk, the list of allowed values must be built dynamically at runtime.

6.2.1.6 Discard invalid input


If your validation function detects invalid input, don't try to "repair" that input. Discard it, log the incident and raise
an error.
Just make sure you use generic messages when communicating the error to a user.
Use a message like "An error has occurred. The administrator has been informed." Do not reveal information
that attackers could use in order to identify more closely where the problem came from.

6.2.1.7 Don't rely on a specific order of requests WASC: 6.4 Insufficient Process Validation
If your program requires that certain process steps are executed in a specific order, you must enforce that this
order can’t be changed. Otherwise important steps could be skipped.
Don't rely on client-side process logic to enforce the correct order. Always implement a server-side mechanism.

6.2.1.8 Don't trust any client-side validation


As the client software is under control of the attacker, the client software itself cannot be trusted. More precisely:
any assumption on what the client software does can be tricked by attackers.
Some important aspects are:
• Any kind of script validation performed on the client can’t be trusted. The scripts could have been
changed.
• UI restrictions could have been bypassed. Hidden fields, values of select boxes, URL parameter in form
destinations could all be changed. Disabled fields could be activated. Length limitations could be
altered.
• Meta information could be changed. This includes HTTP referrer, browser name and version, cookie
values.
Whenever processing data from a client system, one should make sure to perform all important validation tests
on the server. Any assumption that data from a client is delivered in an expected format is a security risk.

Output Encoding
This section describes best practices regarding output encoding. Whenever data is passed on to another
processing context (output context), developers must take care that their input does not contain commands that
are unintentionally interpreted by this output context. An attack that transports commands in data is referred to
as In-Band Signaling. Most of the current top vulnerabilities are caused by output encoding defects. The
requirements in this chapter apply to all data that that is passed to another processing context.

6.2.2.1 Identify and document all output contexts


Whenever you concatenate user input with syntactic text, you most probably have an attackable output context.
Ask yourself: Will the string I build by concatenating user input with my own textual structure be interpreted or
parsed by another process? If the answer is yes, you found an output context.
Document all output contexts you feed input to. Write down the type of context (e.g. SQL, log file, etc) and where
it is invoked in your code.

6.2.2.2 Identify dangerous characters for any output context

Page: 219 of 227


If you write user input to an output context, analyze which characters in user input might be capable of altering
the semantic of the statement you build. For example, if you write data into an HTML context, HTML tags in input
would be considered dangerous, as they can alter the HTML structure.
Look for important characters or commands in that output context. For each output context you use, write down
which characters or commands inside input you consider dangerous.

6.2.2.3 Document the way you encode those meta characters


Once you have identified critical characters and commands, think about how to escape them. Escaping in that
context means altering the character in a way that it is not interpreted as a command or control character
anymore but its representation as data is not changed. Check which escaping functions are provided by your
programming environment before writing your own! Document which escaping function you use to mitigate the
risk of an In-Band Signaling attack.

6.2.2.4 Escape all data for any given output context


Once you have identified one or more methods to escape data, apply them to all instances where your data is
written to the output context. Attention: It is absolutely important to perform escaping at the last possible point
before data is written to the output context. If you escape too early you will run into problems, if data is also
passed to a different output context, as your escaping function may damage data for any context other than the
one it was designed for.

Access management
OWASP: A7 - Broken Authentication and Session Management
This section describes best practices regarding authorization. However, it is not a guideline how to create a role
or authorization design for applications.

6.2.3.1 Perform authorization checks for any access to sensitive information / functionality WASC:
1.2 Insufficient Authentication & 2.2 Insufficient Authorization
All pages after a login screen must check if the current user is privileged to access them. All functionality that
performs read or write access to confidential data must check if the current user is privileged to access this data.
The authority check must also discern between create, read, write and delete access privileges.
All functionality that performs privileged operations (e.g. administrative tasks) must check if the current user is
privileged to execute them. Document how and where your solution performs authority checks.
Information management WASC: 5.2 Information Leakage
This section describes best practices regarding transfer and storage of confidential information. Confidential
information in this context is any information that is not explicitly declared public. This holds true for any
reference to the term confidential in this entire document. This includes but is not limited to: usernames,
passwords, private data, medical data, internal system names, cryptographic keys and payment information.

6.2.4.1 Do not store confidential data in plain text


OWASP: A8 - Insecure Cryptographic Storage
Any information that is not encrypted can be disclosed to malicious users, when they gain access to the location
the information is stored (e.g. file or database table). Therefore, encrypt all confidential information as a second
line of defense. When you need to encrypt confidential data, please make sure the encryption algorithm you
choose is approved for your company or customer.
Document where your solution uses encryption and which algorithms you implemented.

6.2.4.2 Do not hard-code confidential data in your software


Do not assume that malicious users have no access to your source code. Therefore, never store any hard coded
confidential information in your code. Confidential information should be stored in a _le or database residing on
the server in an encrypted form. When your code requires access to the information, load and decrypt them at
runtime.

6.2.4.3 Do not disclose detailed error messages to users

Page: 220 of 227


OWASP: A6 - Information Leakage and Improper Error Handling
Malicious users often try to force error conditions in order to gain internal information from the corresponding
error messages. In all instances where your software generates error messages, make sure those messages
• Are as generic as possible, e.g. "We are very sorry, an error occurred."
• Indicate to the user that the problem was logged and will be taken care of ASAP
• Do not reveal internal system information
• Do not provide technical hints on what caused the error

6.2.4.3.1 Example
After a failed login attempt, simply state that "Login failed due to incorrect credentials."
Do not state that "The password is incorrect", as this would tell a malicious user that he already provided the
correct username.

6.2.4.4 Do not expose data to the user when you do not have to
Always display information on a "need to know" basis. The less information you display to legitimate users, the
less information can be disclosed to malicious users if they exploit a security defect.

6.2.4.4.1 Example
A change password page should not reveal current username or password to the user, as this is not needed for
the task.

6.3 Avoiding common vulnerabilities


This chapter contains a list of common security defects. Since malicious users tend to know such vulnerabilities
they will test for them first. It is therefore absolutely crucial to avoid these types of security defects.

SQL Injection OWASP: A2 - Injection Flaws WASC: 4.5 SQL Injection


Relevance: SQL Injection is relevant whenever SQL statements are built that contain user input.
Problem: If input data contains special SQL characters or SQL commands, it is possible to manipulate the
outcome of an SQL statement. That way, attackers might get unauthorized access to data or manipulate or
delete database contents.

Page: 221 of 227


Solution: All application data that is concatenated into an SQL statement must be properly encoded against SQL
Injection attacks. Whenever applicable, prepared statements should be used to communicate with SQL
databases; in that case, proper encoding will be handled by the database driver.
Further Information:
• http://en.wikipedia.org/wiki/Sql_injection
• http://www.hdm-stuttgart.de/~ms096/SQLInjectionWhitePaper.pdf

Directory Traversal
OWASP: A4 - Insecure Direct Object Reference
WASC: 5.3 Path Traversal
Relevance: Directory Traversal is relevant whenever _le locators are (partially) built on user input. Problem:
If malicious users can manipulate _le locators, they can force the program to access files of their choice.
This can result in information disclosure in case restricted files are displayed. It can also result in data
corruption and Denial of Service attacks, in case files are changed.

Page: 222 of 227


Solution: Do not base file locators on user input.
Further Information:
• http://www.owasp.org/index.php/Path_Traversal
• http://en.wikipedia.org/wiki/Directory_traversal

Command Injection OWASP: A2 - Injection Flaws WASC: 4.4 OS Commanding


Relevance: Command Injection vulnerabilities can arise when (OS layer) commands are (partially) based on
user input.
Problem: Malicious users could change the command through specifically crafted input. This allows for execution
of arbitrary commands on the server and can lead to a total system compromise.

Page: 223 of 227


Solution: Never include user input into an external command. Document where your solution executes (OS
layer) commands.
Further Information:
• http://www.owasp.org/index.php/Command_Injection
• http://en.wikipedia.org/wiki/Command_injection

7 MODIFICATION AND ENHANCEMENTS


This section will describe the Linc specific rules for how to handle the modification and enhancements

7.1 Coding in any Standard Object


When there is a need to write a code in any standard object, for instance user exit, routines, etc.
the code should not be written directly in the standard object, but should be written in a custom
developed object. Calling of this custom object should be the only line of code to be written in the
standard object.

This helps to have a better control, when it comes to activate / deactivate the code written in the
standard object and also helps the Code Profiler tool to scan the changes made in the object.
(Code Profiler ignores all changes made in standard objects).

As an example –
Coding Explanation

Page: 224 of 227


MV45AFZZ
In the SAP module, which contains the
FORM USEREXIT_MOVE_FIELD_TO_VBAK. exits, only includes are added.
… INCLUDE One include in each exit form routine
zSDIWW_MV45A_UE_M2VBAK_D. itself, which will contain the calls.
… Includes at the end of the SAP include,
ENDFORM. which will contain the called form
… routines.
FORM USEREXIT_MOVE_FIELD_TO_VBAP. In the SAP module itself no coding is
INCLUDE zSDIWW_MV45A_UE_M2VBAP_D. done!

ENDFORM.
….
INCLUDE zSDGWW_MV45A_UE_M2VBAK_F
INCLUDE zSDGWW_MV45A_UE_M2VBAP_F
zSDIWW_MV45A_UE_M2VBAK_D The include, which was inserted in the
form routine of the exit, only contains calls
* CHECK, WHETHER EXIT IS TECHNICALLY and performs.
ACTIVE CALL … (EXPLAINED BELOW) The first call checks the technical
* CALL FORM ROUTINES WITH EXIT activation, the next ones implement the
FUNCTIONLITY exit functionality. Within each exit
PERFORM ZZ_… functionality, another check based on
PERFORM ZZ_… sales org, company code, or various other
values should be made in order to restrict
the functionality as per the requirement
per country.
zSDIWW_MV45A_UE_M2VBAK_F
The include with the form routines
FORM ZZ_… ... contains the exit coding.
ENDFORM.
... FORM
ZZ_… ...

Coding Explanation
ENDFORM.

ZZ_PICKUPDATA The form routine, which contains the exit


coding itself, has to start with calls of
FORM ZZ_PICKUPDATA function modules. These function modules
CALL FUNCTION …. (LOOK AT CHAPTER ERROR! check whether the exit is active from
business view. (Look at chapter Error!
REFERENCE SOURCE NOT FOUND.)
Reference source not found.)
CALL FUNCTION …. (LOOK AT CHAPTER ERROR!
REFERENCE SOURCE NOT FOUND.)

* NOW START THE EXIT CODING

ENDFORM.

Compared to Customer-Exits and BADIs it is not possible to deactivate User-Exits. Therefore a


global functionality is provided to achieve that requirement.

Page: 225 of 227


In every User-Exit the functionality has to be called, which checks, whether the User-Exit is
technically activated or not. This has to be done in the following way:
• The function module zBCFGWW_USREXIT_CHECK has to be called as first in each
subroutine or module, which is a user-exit. This function module checks, whether the exit is
active or not. When the exit is not active, the code following is not executed.
Example:

zSDIWW_MV45A_UE_M2VBAK_D.

* Do not execute exit code, when exit is deactivated or not registered


CALL FUNCTION 'zBCFGWW_USREXIT_CHECK' EXPORTING
i_include_name = 'MV45AFZZ'
i_user_exit = 'USEREXIT_MOVE_FIELD_TO_VBAK'
EXCEPTIONS
OTHERS = 3.
IF sy-subrc <> 0.
EXIT.
ENDIF.

* CALL FORM ROUTINES WITH EXIT FUNCTIONLITY


PERFORM ZZ_…
PERFORM ZZ_…

• By default, the exit is deactivated. To activate the User-Exit an entry has to be made in the
customizing table zBCTUSREX.
• Second check to be made is by calling the FM - /LIG/BCFGWW_USREXIT_CHECK_* (where
* denotes a number 00, 01, 02 and so on. Each FM has it’s own set of input parameters based
on which a check can be made. Depending on the standard values available, the appropriate
check FM is to be used.

In all other standard objects, other than user exits, even if there is a standard mechanism to
activate / deactivate the requirement, the above mentioned check should be implemented in every
custom code to be written in any standard object.

7.2 Soft (Hard) Coding


Many a times, it is required to restrict a functionality based on sales org, company code, plant, and
many other parameters. Generally a hard code check is used to achieve such a functionality. But
this kind of hard coding is expensive in terms of maintenance and future extension.

To avoid such situations, we should use a bespoke customizing table should be used.
As an example, table zXXT_DEVCUST is a table extensively used.

Effort should be made that fetching of data from such tables are made generalized in a class /
report etc and should not be fetched for each and every requirement within the same object.
Subsequently after fetching the data from the table, READ statements should be used for each
functionality check.

As an example -

* Select the customizing table entry


SELECT * FROM zxxt_devcust

Page: 226 of 227


INTO TABLE gt_devcust
WHERE modul = 'PP'
AND progname = 'zMPPGWW_PCSGI00'
AND vkorg = l_vkorg.

IF sy-subrc <> 0.

CONCATENATE l_vkorg+0(2) '*' INTO l_vkorg.


SELECT * FROM zxxt_devcust
INTO TABLE gt_devcust
WHERE modul = 'PP'
AND progname = 'zMPPGWW_PCSGI00'
AND vkorg = l_vkorg.
IF sy-subrc <> 0.
* do nothing
ENDIF.
ENDIF.

Once the data is selected then wherever the functionality is required to be checked, a READ
statement should be used.

As an example –

* Read the table for the Parameter value


SORT gt_devcust BY p_param1 y_value1.
READ TABLE gt_devcust WITH KEY p_param1 = 'SHIP_TO_ADDRESS'
y_value1 = gc_true
TRANSPORTING NO FIELDS.
IF sy-subrc = 0.
g_coa = gc_true.
ENDIF.

Page: 227 of 227

Вам также может понравиться