Very often I am approached by developers, technical consultants and SAP enthusiast with the following question.
“What is the optimal way of writing code in ABAP? Is there any model or principle that should be followed?”
Well today I will take the opportunity to explain a few aspects of Clean Design that should be followed while coding in ABAP, or rather one should adhere to while coding in ABAP.
But before I move ahead, I would like to give you a short background on ABAP. Of course everyone of us are well aware of the history of ABAP. But I feel this is important to know before we move ahead.
The initial R/3 days ABAP was developed as a procedural language, unlike the other procedural languages of the era. But with the introduction of Object Oriented ABAP, it has adapted to the principles of object oriented programming. It’s now similar to any other popular object oriented programming languages like java or C++, as it has concepts like inheritance, polymorphism, class & objects.
Today, object oriented ABAP is used more often to simplify the overall programming model.
Key features of Object Oriented ABAP are the following:
- Data abstraction and encapsulation
- Code redundancy minimal
- Enhanced data-security & access
- References can be drawn from real-world entities and used in modelling
- Forms an effective programming structure.
Now having said this, most of you might have guessed where the discussion is tending to.
Clean Design of Classes
Now most of us need to develop a class here and then to support various business objectives. And to do so, the easiest way, many of us choose is to create static classes with static methods and put our code into these methods and consider our job is done.
But do we consider the following points:
Are we actually imbibing the Object Oriented Behavior?
Does our class have any authenticity?
Well, to answer the first question. NO, we are not following the object oriented behavior. And to answer the second question, the authenticity of a class can be proved if it has a test class associated to it.
So let’s start with a simple example of a static class.
Now in this example, there is no abstraction nor encapsulation. Also, data security and access is NULL. Any body consuming this class, can access the members and can change the value of it. Also, the sole purpose of OOPs of having member functions, i.e., methods which operate on the members goes for a toss. Another, aspect from the authenticity point of view, no double class can be created and injected for this class during testing.
So, how can we address such a situation?
- Always define methods and attributes as instance components.
- Use singleton pattern only if really required.
This is a better design than before, as the attribute is private now. Hence, security and access to the data in the class is only possible via the method(s). So now we have restricted the member of the class to be manipulated by any consumer. Also, since there is no static method, a consumer needs to generate an instance to access the member functions, i.e., the method(s). So the member functions are bound to the instances generated. However, still the design is not perfect. Consider the following scenarios.
- A user class needs to refer to this class. Therefore, it is not possible to replace this class with another class without changing the user class.
- From testing purpose a double class needs to be a subclass of this class. Therefore this class cannot be final.
So, the above limitations can be removed by introducing an interface. User classes can refer to the interface and thus concrete on the methods and attributes they need. All other methods and attributes are private or protected and thus hidden or abstracted. Only immutable & read only attributes are public.
Again, this is a better design but not very much on the cleaner side. We are able to remove the dependency of the user class which refers to our class by providing an interface for implementation by the user classes which needs to refer to our class. Also, as per to testing purpose, the double creation is now possible by using the interface, thus our class can be made final now.
However, for a consumer class, object creation is technical and complex as the constructor will have to offer optional parameters to allow the creation of different type of objects (use cases). And if the constructor contain all the logic and dependencies, these are going to be a part of every unit test and need to be inherited by subclass doubles. Also, by the look of the constructor we cannot ensure that if the class is singleton or not.
As a savior to above described limitation, offering at least one creation method per object type will allow simple and readable object creation with fewer (mostly non-optional) parameters. To enforce the exclusive use of the creation methods, the instantiation of the class needs to be made private. Also, by the labeling of the creation methods, we can clearly denote, if the instance to be returned is of singleton nature or not. [get for singleton instances and create for non-singleton instances]
This is a far better design than from what we had started. However, still there is a direct dependency from the class as the static creation method will be used. If many classes consumes this class, they will use the static creation method offered to instantiate the class. If tomorrow we need to replace the class with some other class, all the consuming classes needs to be modified. Also, a user class cannot collaborate with double class for isolated tests.
Hence, a better design will be to delegate the object creation for this class to a factory class. The user classes are no creator any longer. As global friend, factory class is the only class to access private creation methods of this class.
Now we can consider this to be a clean design, where we have factory to provide us with objects for different scenarios. Also, if tomorrow your class needs to be changed, the creation logic needs to be changed in the factory. Thus the consumer classes are void of any modifications.
This was a humble attempt form my end to explain how classes should be designed using Object Oriented approach adhering to a clean design concept. Kindly comment your feedback on this and if the community likes it, I will be share more content on the clean design aspect. Anyone can reach out to me with their queries on LinkedIn as well.
Since we all in a grave situation because of the COVID-19, lets utilize our free time and contribute as much possible to SAP community to build simple and robust code-base for the future.