SAP SEPARATION CONCERNS - Guide
Get Example source ABAP code based on a different SAP table
Separation of Concerns
ABAP_BACKGROUND
The term 'separation of concerns' (SoC) was coined in <(>Edsger W. Dijkstra's<)> article
Separation of concerns is a principle used in programming to separate an application into units, with minimal overlapping between the functions of the individual units. The separation of concerns is achieved using modularization, encapsulation and arrangement in software layers.
Although the classic three-layer architecture of Application Server ABAP (AS ABAP) is ideal for ABAP programming based on the SoC principle, this possibility was never explored. Application programs (in other words, dialog programs in module pools or reports in executable programs) were usually displayed as monolithic blocks, in which the system simultaneously reacted to user actions of the presentation layer, completed the application logic and executed accesses to data on the persistency layer. This type of programming is no longer relevant in today's programming world, where concepts like service-oriented architecture (
ABAP_RULE
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 from the logic of the presentation logic, persistency, and the logic for communication with external systems. Encapsulate the repository objects of the individual concerns in separate packages.
ABAP_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:
Regarding the last point, it would even be true to say that following the SoC principle is a prerequisite for executing isolated, automated
ABAP_EXAMPLE_BAD
The following figure shows two examples of an ABAP application that do not follow the SoC principle.
IMAGE ABDOC_SOC_bad.jpg 590 400
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 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.
alv TYPE REF TO cl_salv_table,
alv_exc TYPE REF TO cx_salv_msg.>
FROM spfli
WHERE carrid = @p_carrid
INTO TABLE @spfli_tab.>
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 works in the same way 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.
PARAMETERS p_carrid TYPE spfli-carrid.
SELECTION-SCREEN END OF SCREEN 100.>
table TYPE spfli_tab,
arc TYPE sy-subrc.>
PERFORM get_carrid CHANGING carrid.
PERFORM get_table USING carrid
CHANGING table
arc.>
PERFORM sort_table CHANGING table.
PERFORM display_table USING table.
ENDIF.>
CHANGING value(carrid) TYPE spfli-carrid.
CALL SELECTION-SCREEN 100.
IF sy-subrc = 0.
carrid = p_carrid.
ENDIF.
ENDFORM.>
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(
IMPORTING 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.>
CHANGING table TYPE spfli_tab.
SORT table BY cityfrom cityto.
ENDFORM.>
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.
ABAP_EXAMPLE_END
ABAP_EXAMPLE_GOOD
The following figure shows how an ABAP application should look that follows the separation of concerns.
IMAGE ABDOC_SOC_good.jpg 500 430
After the concerns have been identified, they are implemented in ABAP object classes. The concerns shown in the figure are the main tasks that are usually performed in ABAP application programming:
These main rules can be subdivided further, which is often necessary.
The boxes for the individual concerns in the figure represent packages. All the repository objects (classes, data types) belonging to a concern should be located in corresponding packages. The package concept (encapsulated packages) supports this separation of concerns. In encapsulated packages, repository objects in one package can only access the objects of another package using package interfaces, which is checked by the syntax check. A package can restrict the usability of its repository objects even more by using access control lists. Subdividing the separation of concerns in a package is a concept supported by subpackages.
For example, encapsulating all database tables of an application in a package for persistency services prevents any program, that does not belong to this package, from accessing these database tables. The reverse is also true. For example, programs in the persistency layer cannot communicate directly with components in the presentation layer, such as a Web Dynpro ABAP application. You should prepare the package encapsulation (by choosing
The following source code shows how to adapt the separation of concerns from the above source code for classes local to the program.
SELECTION-SCREEN BEGIN OF SCREEN 100.
PARAMETERS p_carrid TYPE spfli-carrid.
SELECTION-SCREEN END OF SCREEN 100.>
PUBLIC SECTION.
CLASS-METHODS:
get_carrid RETURNING VALUE(carrid) TYPE spfli-carrid,
display_table IMPORTING VALUE(table) TYPE spfli_tab.
ENDCLASS.>
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(
IMPORTING 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.>
PUBLIC SECTION.
CLASS-METHODS
sort_table CHANGING table TYPE spfli_tab.
ENDCLASS.>
METHOD sort_table.
SORT table BY cityfrom cityto.
ENDMETHOD.
ENDCLASS.>
PUBLIC SECTION.
CLASS-METHODS
get_table IMPORTING carrid TYPE spfli-carrid
EXPORTING table TYPE spfli_tab
arc TYPE sy-subrc.
ENDCLASS.>
METHOD get_table.
SELECT *
FROM spfli
WHERE carrid = @carrid
INTO TABLE @table.
arc = sy-subrc.
ENDMETHOD.
ENDCLASS.>
PUBLIC SECTION.
CLASS-METHODS main.
ENDCLASS.>
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(
CHANGING table = table ).
presentation_server=>display_table( table ).
ENDIF.
ENDMETHOD.
ENDCLASS.>
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 incurred by wrapping the concerns in classes. If the reuse options for
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).
ABAP_EXAMPLE_END