Hula Hubba
Hula Hubba
Hula Hubba
and
Version 2.0
Quality Approval
Author
Reviewed / Approved
Quality Approved
Document History
1.0
1.1
Page: 1 of 227
1.2
2.0
Page: 2 of 227
Document References
Page: 3 of 227
1 General Rules .................................................................................... 9
1.1 Separation of Concern ............................................................................................................. 9
Background ......................................................................................................................... 9
Rule..................................................................................................................................... 9
Details ................................................................................................................................. 9
Page: 4 of 227
Statements per Program Line ........................................................................................... 43
Using Pretty Printer........................................................................................................... 45
Line Width ......................................................................................................................... 47
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
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
Page: 7 of 227
Sorted Filling ................................................................................................................... 175
Compressed Filling ......................................................................................................... 176
Output Behavior .............................................................................................................. 177
Loop Processing ............................................................................................................. 178
Page: 8 of 227
Write your code with an attacker's mindset .................................................................... 213
Do not write your own cryptographic functions ............................................................... 214
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.
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.
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.
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
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).
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.
• 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
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.
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:
• 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)
• Dynamic generation of classes as a replacement for the classical dynamic program generation
(GENERATE SUBROUTINE POOL)
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.
• 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.
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.
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.
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.
Page: 26 of 227
TRY.
account1->withdraw( ... ). account2-
>withdraw( ... ).
CATCH cx_negative_amount.
...
ENDTRY.
ENDMETHOD.
ENDCLASS.
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.
• 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.
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:
• 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
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.
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:
• 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
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
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).
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
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.
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.
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.
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.
Syntax Check
2.4.1.1 Background
• 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 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.
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.
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.
Page: 37 of 227
ASSIGN itab[ KEY cities
COMPONENTS cityfrom = '...' cityto = '...' ] TO <fs>.
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 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:
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.
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.
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.
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.
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
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.
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.
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.
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.
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.
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:
• 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
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.
Package 02
• 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 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.
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.
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.
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 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.
• 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:
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:
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.
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.
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.
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.
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.
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
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:
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:
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.
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.
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.
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.
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.
• 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]
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_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:
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
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:
[VISIBILITY][TYPE]_[Descriptive_Name]
TYPE should be the 1-character abbreviation of the elementary data type ( Structure / Table / Constant / …)
The following sections discuss the different aspects of program-internal names in detail and with a systematic
approach.
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.
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.
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.
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.
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.
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.
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.
• 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.
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.
Page: 63 of 227
…….
…….
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.
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 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
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.
The following source code shows the above source code with English comments, as set out in the above rule.
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
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.
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.
In the following source code, the comments in the above example have been replaced with a description of why
something happens.
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
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.
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.
• 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.
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.
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.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
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.
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.
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
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.
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.
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.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
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
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
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.
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.
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'.
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.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
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.
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.
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.
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
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.
For operational statements, however, chained statements are not recommended because they do not usually
result in better readability. Example:
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' ).
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
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.
• 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.
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.
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.
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
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
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.
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 ).
...
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
enable assignments of
• data objects,
• results of calculation expressions (arithmetic expressions, bit expressions, and string expressions) to
Alongside the assignment operators, two obsolete statements exist for historical reasons that can also perform
assignments:
• The statement
• The statement
3.6.4.2 Rule
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 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.
The following source code shows a simple assignment using MOVE and the assignment of an arithmetic
expression after COMPUTE.
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.
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
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:
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:
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.
The following source code shows a multiplication using the statement MULTIPLY.
MULTIPLY n1 by n2.
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
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.
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.
The following source code has the same function as the example above. However, the total is only calculated
once before the loop.
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
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.
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.
The following source code has the same function as the example above. However, the total is only calculated
once before the loop.
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
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
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
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
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
• 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.
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
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).
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:
• 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 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.
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.
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.
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.
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 = ... ).
4.1.3.1 Background
• 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
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.
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).
The following source code shows an implementation of the singleton design pattern. A static method allows
access to the only object of the class.
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, 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.
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.
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
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.
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.
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.
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.
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.
4.1.7.2 Rule
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.
ABAP offers various method for responding to error situations like these.
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
• 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 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.
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.
• 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
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.
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).
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. .
oref->do_something(
EXCEPTIONS application_error = 4 ).
IF sy-subrc <> 0.
...
ENDIF.
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.
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
When creating and raising class-based exceptions, always use an exception category suitable for the current
error situation:
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).
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.
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'.
...
RAISE EXCEPTION TYPE zcx_exception_text
EXPORTING textid =
zcx_exception_text=>zcx_exception_text.
...
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
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.
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.
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.
4.2.6.2 Rule
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.
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.
4.2.7.2 Rule
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.
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.
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
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.
...
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:
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
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.
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.
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.
4.3.1.2 Rule
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.
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.
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
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:
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
A classic dialog program - usually a single module pool - processes all the facets of an application.
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.
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
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
• 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.
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.
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.
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:
• 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.1.1 Background
ABAP programs can have both read and write access to data in the following persistent storage media:
According to the SoC principle, such accesses are wrapped in service classes of the persistency layer of an
application.
4.4.1.2 Rule
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.
4.4.2.1 Background
• 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
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
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.
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.
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.
4.4.3.2 Rule
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.
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.
The following source code shows how Open SQL is generally used for implicit automatic client handling.
4.4.4.1 Details
• 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:
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:
• 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).
This makes the application program more legible, more robust, and easier to maintain.
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.
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.
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:
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.
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:
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.
• 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.
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.
Use standalone data types instead of constructing bound data types when declaring data objects.
5.1.1.3 Details
• 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.
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.
...
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.
5.1.2.1 Background
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 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:
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.
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.
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,
...
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=>.
Declaration of Variables
5.1.3.1 Background
• Program-local:
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 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.
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:
In these cases, you have to ensure the maximum possible encapsulation of those global variables.
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.
...
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
• 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 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.
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
ENDMETHOD.
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
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
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 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).
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.
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,
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 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.
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.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
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.
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.
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.
...
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.
TABLES table_wa.
NODES 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.
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
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
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:
• IF sy-subrc = 0.
• 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.
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.
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 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.
• 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.
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.
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.
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.
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.
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.
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.
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
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.
The following source code shows an unsuitable emulation of the boolean data objects not present in ABAP.
The following source code shows the recommended emulation of the boolean data objects not present in ABAP.
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.
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.
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.
The following source code hows how code can be improved compared to the previous example, so that no
conversions are necessary.
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:
5.2.2.2 Rule
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.
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.
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.
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.
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:
• 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
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
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.
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.
This issue is corrected in the source code below. The EXACT operator is used, which triggers an exception.
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
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 ' '.
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.
text = '123'.
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 `.
text = '123'.
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".
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-
5.2.5.2 Rule
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.
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.
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.
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.
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 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
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.
• 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.
• 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
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.
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.
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.
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
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.
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.
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
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.
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.
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. If a cast to another data type is required, it can usually be implemented explicitly using
ASSIGN ... CASTING.
5.2.9.3 Details
• Using structures in operand positions where elementary data objects are expected
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.
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.
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> = ...
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:
• 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
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.
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.
The following two source codes illustrate how the above example can be changed to avoid runtime errors using
prevention or exception handling.
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.
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.
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 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
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.
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.
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.
...
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.
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
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.
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.
...
The source code below omits the write access shown above.
CALL FUNCTION...
...
EXCEPTIONS ...
CASE sy-subrc.
...
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
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.
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.
The following source code demonstrates how decimal places can be counted correctly using the appropriate
addition of the statement DESCRIBE FIELD.
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
5.3.3.2 Rule
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.
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.
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.
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 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.
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.
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
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
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.
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.
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.
...
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
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
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.
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
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.
• Row type
• 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.
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).
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
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
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
• 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:
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
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 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.
• 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.
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.
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.
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.
5.4.3.1 Background
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
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.
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.
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.
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
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.
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.
...
...
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
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
• 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
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.
For table expressions, the information here applies to the selection of the appropriate result.
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.
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 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:
These types of accesses to the table body cause problems by producing a loop across the internal table
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.
• 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.
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.
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
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.
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.
• 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.
• 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.
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.
The following source code corrects the above example by declaring the parameter as an input/output parameter
with CHANGING according to its use.
5.5.3.1 Background
• 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
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.
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
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.
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
• 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 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
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.
Using the predefined function condense produces the same behavior when a blank is passed, regardless of the
fixed type.
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).
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.
...
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 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
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 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'.
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:
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.
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.
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.
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.
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
• 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 Reporting events that occur during the processing of an executable program (with a logical
Selection screen events (AT SELECTION-SCREEN ...) o List events of classic list
5.5.8.2 Rule
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:
• Dialog modules and AT SELECTION-SCREEN when classic dynpros and selection screens are
processed
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
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
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:
• 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.
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'.
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.
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.
5.6.1.1 Background
• 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)
• 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.
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.
• 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.
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.
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.
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.
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
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.
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
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:
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.
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:
• Anonymous data objects created using CREATE DATA and addressed using data references in data
reference variables
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
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 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.
Releasing Memory
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:
• 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.
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 ...
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.
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.
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.
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
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 Explicit casting
ASSIGN ... CASTING ...
• 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.
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.
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 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.
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.
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.
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.
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.
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.
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:
• Message texts
• Text pools of ABAP programs that include the text elements of the program, for example, text symbols
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
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.
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.
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.
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
Create placeholders in message texts with the unique names &1, &2, &3, and &4 only.
5.7.2.3 Details
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
If this message text was translated to The entry & was not found in table & a
and
The entry &2 was not found in table &1 a MESSAGE statement when logged
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.
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
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.
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.
5.7.4.1 Background
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 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
5.7.5.2 Rule
Make sure that statements do not cut character strings in any places with composite characters or surrogates.
5.7.5.3 Details
• 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.
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
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
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.
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.
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.
6 SECURITY
6.1 Security Principles
This section describes several common sense best practices to follow during design and development.
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.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.
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.
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.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.
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.
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
Coding Explanation
ENDFORM.
zSDIWW_MV45A_UE_M2VBAK_D.
• 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.
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 -
IF sy-subrc <> 0.
Once the data is selected then wherever the functionality is required to be checked, a READ
statement should be used.
As an example –