Skip to Content

In my OO Programming with ABAP Objects: Classes and Objects blog entry, I introduced the concept of classes and objects, showing you how to create and use both in ABAP Objects. If this is your first exposure to OO programming, you might be wondering what’s so great about it. After all, on the surface, a class looks a lot like a function group or subroutine pool. In this blog, we will dig deeper to see where classes differentiate themselves from procedural concepts.

What’s Wrong with the Procedural Approach?

One common misconception about OO programming is that it is different from procedural programming in every way – not true. There are many important lessons to be taken from the procedural approach. However, there are certain limitations of this approach that influenced early researchers in their design of the OO paradigm. These limitations are best described with an example. Let’s imagine that you want to build a code library to make it easier to work with dates. To do so, you create a function group called ZDATE_API that contains various function modules to manipulate and display dates.

From a data perspective, you have a couple of options. Function groups allow you to define group-specific data objects that can be utilized within function modules (similar to the use of attributes in methods). However, in practice, such data objects can be difficult to use. This is because it is not possible to create “instances” of function groups. For example, in the ZDATE_API function group, I might define a global data object of type SCALS_DATE to keep track of the date being manipulated by the function modules. However, if I need to keep track of multiple dates in my program (e.g. created on date, changed on date, document date, etc.), I need to build an internal table to keep track of each date “instance”. I also need to keep track of the key to this table externally – otherwise I have no way of identifying a particular date instance. This limitation causes most developers to keep track of their data objects outside of the function group. If you think back to the last time you tried to call a BAPI and all the data objects you had to define beforehand, you’ll appreciate what I mean. We’ll explore some of the implications of this approach to data in a moment.

Assuming that we elected to keep track of data separately, let’s look at what a function module might look like in our ZDATE_API function group. For the purposes of this discussion, we’ll keep it simple and just look at a function module used to set the “day” value of the date:

FUNCTION z_date_set_day.
  * Local Interface IMPORTING VALUE (lv_day) TYPE I
  *                 CHANGING (cs_date) TYPE SCALS_DATE
  *                 EXCEPTIONS invalid_date
  DATA: lv_month_end TYPE i. “Last Day of Month

  CASE cs_date-month.
    WHEN 1.
      lv_month_end = 31.
    WHEN 2.
      …
  ENDCASE.

  IF iv_day LT 1 OR iv_day GT lv_month_end.
    RAISE invalid_date.
  ELSE.
    cs_date-day = iv_day.
  ENDIF.
ENDFUNCTION.

This contrived example simply ensures that we initialize the “day” value of a date to a proper value. Clearly, there are probably better ways to implement something like this, but the point is that we have defined some business rules inside of a function module that is part of an API designed to simplify the way that we work with dates.

Now that we have our function group in place, let’s imagine that you are asked to troubleshoot a program that is using your function group to display dates in various formats but it is outputting them incorrectly (e.g., 02/31/2009). At first, you might think that there is a problem with Z_DATE_SET_DAY as the day value is incorrect. However, after further review, you discover that the invalid assignment was made in the program itself. After all, there’s nothing stopping a program from changing the day value of a local variable directly. To that program, the day component of the SCALS_DATE structure is nothing more than a 2 digit numeric character with a valid range of 00-99 – the semantic meaning of the day value is defined within the confines of our ZDATE_API function group.

Beyond the issue of data corruption, think about how clumsy the typical function group is. The separation of data and behavior in the ZDATE_API function group limits the usefulness of the abstraction, making the use of the API awkward as we have to pass the SCALS_DATE object back and forth between function calls. This becomes something more than a nuisance when the library expands. For example, think of the impact of expanding this API to support timestamps. A better approach would be to hide this data such that callers don’t have to worry about it.

Hiding the Implementation

In programming terms, a function group like ZDATE_API is an abstract data type (or ADT). As the term suggests, an ADT abstracts a particular concept into an easy-to-use data type. Ideally, the creation of a date API would imply that we no longer need to worry about how dates work. Rather, we can leverage the hard work (and testing) that went into the creation of the date API and focus in on other important tasks. However, this is difficult to do if the ADT is not well encapsulated. The term encapsulate implies that we’re combining something into an enclosure (or capsule). In the case of an ADT, we’re grouping data and behavior together. Moreover, encapsulation also suggests that we are protecting these resources from external tampering. Initially, most programmers balk at this, preferring to have complete control over all parts of the code. The problem with this is that taking control of any code also implies that you assume some of the risk for ensuring that it operates correctly. In our date example, look at how problematic it was to allow external programs to modify the date structure. Ideally, we would prefer that any modifications to this structure pass through business rule checkpoints to make sure that data is not corrupted.

Encapsulation is a good engineering practice used in many disciplines. For instance, you don’t have to know how a car works in order to drive it. Of course, it does help if you have power steering, automatic transmission, etc. These features represent the “interface” that users utilize to interact with the car. ADTs also have an interface (namely the signature of the function modules, method, etc.). Good interface design should make it easy to use an API without diminishing any of its capabilities. Another advantage of this engineering approach is that parts become more interchangeable. For example, imagine that a car manufacturer decides to redesign their fuel injector to improve performance. As long as the new fuel injector has the same interface (e.g. same “hookup”), the manufacturer can swap the parts and nobody’s the wiser. In my next two blogs, I’ll show how inheritance and polymorphism allows you to do some powerful things here with your OO programs.

Hopefully by now you agree that it is a good idea to group data and behavior together in a class. This, by itself, does not mean that a class is encapsulated. Remember, to achieve this, we must also place a protective capsule around the resources. OO languages such as ABAP Objects allow you to define component visibilities using access specifiers. The following class shows how to define these component visibilities:

CLASS lcl_visible DEFINITION.
  PUBLIC SECTION.
    DATA: x TYPE i.
  PROTECTED SECTION.
    DATA: y TYPE i.
  PRIVATE SECTION.
    DATA: z TYPE i.
ENDCLASS.

As you can see, the components of class lcl_visible are partitioned into three distinct sections: the PUBLIC SECTION, the PROTECTED SECTION, and the PRIVATE SECTION. Components defined in the PUBLIC SECTION are visible everywhere. Components defined in the PRIVATE SECTION are only visible within the class itself. Thus, the only place that you can access the attribute “z” would be inside of an instance method of class lcl_visible. We’ll talk about the PROTECTED SECTION when we talk about inheritance.

In this way, we can reproduce our date API in a class like this:

CLASS lcl_date DEFINITION.
  PUBLIC SECTION.
    METHODS: set_month IMPORTING im_month TYPE i
                       EXCEPTIONS invalid_date,
             set_day   IMPORTING im_day TYPE i
                       EXCEPTIONS invalid_date,
             set_year  IMPORTING im_year TYPE i
                       EXCEPTIONS invalid_date.
  PRIVATE SECTION.
    DATA: date TYPE scals_date.
ENDCLASS.

CLASS lcl_date IMPLEMENTATION.
  METHOD set_month.
    “Implementation of method set_month goes here…
  ENDMETHOD.

  METHOD set_day.
    DATA: lv_month_end TYPE i. “Last Day of Month

    CASE date-month.
      WHEN 1.
        lv_month_end = 31.
      WHEN 2.
        …
    ENDCASE.

    IF iv_day LT 1 OR iv_day GT lv_month_end.
      RAISE invalid_date.
    ELSE.
      date-day = iv_day.
    ENDIF.
  ENDMETHOD.

  METHOD set_year.
    “Implementation of method set_year goes here…
  ENDMETHOD.
ENDCLASS.

Notice that the “date” attribute is defined in the PRIVATE SECTION of the class. Now, any accesses to the “date” attribute must go through public instance methods. This ensures that an external program cannot accidentally (or purposefully) modify the value incorrectly. It also makes the date API easier to use as client programs now only need to define dates like this:

DATA: lr_date TYPE REF TO lcl_date.

With a simple API like this, it’s not such a big deal. However, consider how you might implement an API for working with SAP Business Partners, etc. Having the objects keep track of all that data simplifies API use considerably.

Reflections

As you have seen in this blog, encapsulation is a good engineering practice that you can use to develop quality reusable class libraries. I emphasize reusable here to demonstrate an important point. One of the most common reasons why a library is not reused is because it has too many dependencies. Developing classes using implementation hiding techniques forces you to enter into a mindset whereby classes begin to take on a certain amount of autonomy. In other words, you start to ask yourself questions like “What data does an object of my class need in order to do its job?”, etc. Once you have figured this out, you design your interface in such a way as to only provide what the class with what it needs – reducing unnecessary dependencies along the way. The fewer dependencies a class has, the less likely things are to go wrong. And, as we will see in my next blog, it also allows us to expand our libraries in interesting ways without jeopardizing code that has been proven to work.

To report this post you need to login first.

8 Comments

You must be Logged on to comment or reply to a post.

  1. Bhavani Prasad Bandi
    The beauty of ABAP is its ease of readability and simplicity. Even a business consultant can easily read and understand the language and functionality behind it. OO ABAP is only effective when you are writing big applications or atleast applications with independent data models and some heavy duty processing required around the data. SAP can use all the OO techniques in building the applications achieving full measure of effectiveness in terms of achieving the good design – but programmers at clients do not have time to think and design OO approach which can be solved by simple procedural techniques. As more and more modules in SAP are getting less and less customized by programming, I don’t see OO ABAP getting anywhere.

    As for Java stack, its entirely another matter. As more applications and environments in SAP begin to use Java, any customizations needed in this area will have to follow OO approach for any additional programming.

    Just thinking aloud.
    -B P

    (0) 
    1. Naimesh Patel
      Hello BP,

      I don’t agree with you. Programmers have to start thinking & implementing with using the OO ABAP where ever is possible. If they have used the OO for small – small applications, then you can combine them and hide all the complexity from the calling application.

      “As more and more modules in SAP are getting less and less customized by programming” and how does SAP is doing this? By using the OO ABAP. Like SALV model to hide all the complexity of using the different type of ALVs.

      Regards,
      Naimesh Patel

      (0) 
    2. James Wood Post author
      Thanks for the feedback. You make an interesting observation. In my experience however, I routinely encounter custom development efforts that could benefit greatly from OO design principles. Indeed, this need is increasing with the advent of so much Web-based development (e.g. Web Dynpro for ABAP, BSPs, etc.). And, while I would agree that ABAP is easy to read, I would argue whether or not the typical business consultant could read the average ABAP program. Here, I too often see poorly modularized programs with weak cohesion and little to no documentation. From my perspective, I see OO ABAP as a necessity for improving the productivity of development teams.
      (0) 
    3. Bhavani Prasad Bandi
      May be you are right. My point is that – SAP has used OO ABAP more and more than implementation developers. Its nearly a decade since OO ABAP was introduced. SAP keeps retiring most of its FM’s and makes them into classes with every new release. Developers have been just using what SAP provided, instead of designing their own OO programs.

      Webdynpro ABAP and “traditional ABAP” have nothing in common of how they operate in architectural framework except with some familiarity of syntax. We might have just called Webdynpro something else and it would have been fine. The model of Webdynpro renders everything learnt by traditional ABAP developer irrelevant – again except for some syntax.

      Nevertheless, the data modeling aspect of OO SAP world by the implementation developers remains to be seen – even with the advent of Webdynpro.
      For instance, the kind of example this blog showcases is not sufficient for developers to start adopting OO in their ABAP programming.

      In the end of course, SAP is going Microsoft’s way of pushing their products down the throats of clients whether they like it or not. Once they replace all the business transactions inside SAP with webdynpro’s – OO ABAP may have arrived.

      (0) 
  2. Marcin Byra
    You have written “SCALS_DATE structure is nothing more than a 2 digit”. However this seems to contradict the fact, thet you’re reading both month and day from scals_date:

    CASE cs_date-month.
    cs_date-day = iv_day.

    I am rather beginner in ABAP (that’s why tried to follow your example closely), so I could be wrong.

    (0) 
    1. Marcin Byra
      Sorry for double-posting, but I also do not undestand the OO code:
      You’re importing value of iv_day. I do not see hiowever how structure date is suplied with value i.e. where from comes month (or year).

      Maybe these are details, but first part of your blog (objects and classes) looked like aiming for begginers. Second is not so transparent.

      (0) 
      1. James Wood Post author
        Hi Marcin,

        Yes, I should have been more clear with this. I leveraged this example from my book where I do a lot more setup and explanation – my apologies. I have updated the code so that you can see the other methods outlined here. Hopefully everything will make more sense now. Let me know if it does not.

        Thanks,

        James

        (0) 
    2. James Wood Post author
      Hi Marcin,

      Sorry for the confusion. In that sentence, I actually refer to the fact that the “day” component of the “SCALS_DATE” structure was a two digit numeric character. I should have been more clear here. Does that help though?

      Thanks,

      James

      (0) 

Leave a Reply