GUIDELINE 2.1
Separation of Concerns
ABAP_BACKGROUND
The term 'separation of concerns' (SoC) was coined in Edsger W.
Dijkstra's article On the role of scientific thought from 1974:
"... But nothing is gained --on the contrary!-- by tackling these
various aspects simultaneously. It is what I sometimes have called 'the
separation of concerns', which, even if not perfectly possible, is yet
the only available technique for effective ordering of one's thoughts,
that I know of. This is what I mean by 'focusing one's attention upon
some aspect': it does not mean ignoring the other aspects, it is just
doing justice to the fact that from this aspect's point of view, the
other is irrelevant." (Springer-Verlag, 1982)
Separation of concerns is a principle used in programming to separate an
application into units, with minimal overlapping between the functions
of the individual units. The separation of concerns is achieved using
modularization, encapsulation and arrangement in software layers.
Although the classic three-layer architecture of the SAP system - now
named SAP NetWeaver Application Server ABAP ( AS ABAP ) - is ideal
for ABAP programming based on the SoC principle, this possibility was
never explored. Application programs (in other words, dialog programs
in module pools or reports in executable programs) were usually
displayed as monolithic blocks, in which the system simultaneously
reacted to user actions of the presentation layer, completed the
application logic and executed accesses to data on the persistency
layer. This type of programming is no longer relevant in today's
programming word, where concepts like service-oriented architecture (
SOA ) set the trend.
ABAP_RULE
Following the SoC Principle
Follow the separation of concerns principle. Model your applications
strictly as service-orientated 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.
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:
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
module tests .
Bad example
The following graphic shows two examples of an ABAP application that do
not follow the SoC principle.
In fact, the two bad examples here are the programmer models for
reporting and dialog programming that were propagated by SAP for a
considerable length of time! To be more precise, the example is not bad
due to the reporting or programming of transactions itself, but due to
the way in which these applications are usually implemented. The mini
report in the following source code is a typical example of how
different 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
INTO TABLE spfli_tab
WHERE carrid = p_carrid.
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, subp
rograms). 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 module 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.
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(
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.
* 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
INTO TABLE table
WHERE carrid = carrid.
arc = sy-subrc.
ENDFORM.
However, this separation of concerns using subprograms 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.
Good example
The following graphic shows how an ABAP application should look that
follows the separation of concerns.
After the concerns have been identified, they are implemented in ABAP
object classes. The concerns shown in the graphic are the main tasks
that are usually performed in ABAP application programming:
Communication with a user interface ( UI ) using UI services
Actual application logic
Access to persistent data using persistency services
Communication with external systems using proxy services
These main rules can be subdivided further, which is often necessary.
The boxes for the individual concerns in the graphic represent packages.
All the repository objects (classes, data types) belonging to a concern
should be located in corresponding packages. The package concept
(encapsulated packages) supports this separation of concerns. In
encapsulated packages, repository objects in one package can only access
the objects of another package using package interfaces, which is
checked by the syntax check. A package can restrict the usability of its
repository objects even more by using access control lists. Subdividing
the separation of concerns in a package is a concept supported by
subpackages.
For example, encapsulating all database tables of an application in a
package for persistency services prevents any program, that does not
belong to this package, from accessing these database tables. The
reverse is also true. For example, programs in the persistency layer
cannot communicate directly with components in the presentation layer,
such as a Web Dynpro ABAP application. You should prepare the package
encapsulation (by choosing Package Check as Server ) in the
package properties. These packages have package interfaces, A package
check is performed during the extended program check.
The following source code shows how to adapt the separation of concerns
from the above source code for classes local to the program.
REPORT z_soc_class_report.
SELECTION-SCREEN BEGIN OF SCREEN 100.
PARAMETERS p_carrid TYPE spfli-carrid.
SELECTION-SCREEN END OF SCREEN 100.
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(
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.
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
INTO TABLE table
WHERE carrid = carrid.
arc = sy-subrc.
ENDMETHOD.
ENDCLASS.
CLASS report DEFINITION.
PUBLIC SECTION.
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(
CHANGING 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).
Documentation extract taken from SAP system, � Copyright SAP AG. All rights reserved