Code less, reuse more: Rebels, let’s package our tools!
Packages are one of our foundations to a leaner codebase, but is simply ignored because of a few mistakes done in dark ages of ABAP world. Let´s start fresh again and employ it to our well-being.
After the prologue, this is our first episode: packages and its hidden powers.
Devotopia, once a peaceful and prosperous world, fell down after an unexpected attack from empire. Since that event, inhabitants of this devastated planet have gathered in small villages, hiding into (basement) caves, (wallpaper) woods, helping each other to survive in this decaying era, using their (developers) workbenches to build weapons and use them in a daily faithless fight each day against the oppressor. They knew that if they wanted to reconquer their own planet, they should join once again and collaborate with each other to outpower the empire force.
When you are coding in a development environment, there are only a few times that you are really creating something new. The most part of your work is dealing with some problem or requirement that someone already faced and provided a solution for it. The most obvious hard proof evidence is ALV, a standard tool to display data in tabular format. Whenever you are asked to display data in tabular format on Dynpro you don’t think twice in what to use.
Another example is updating standard data model, you learn (in a good or bad way) that you must use only standard (provided) functions/classes to change data in these models, because they ensure data consistency in various levels, like table lock, rules modelled in customizing, triggering events / post-actions, cascading replication, all that important stuff that a simply direct “MODIFY/UPDATE” in standard table will not handle. You don’t need to fully understand all the intrinsics of standard data models to comply with them, call the provided APIs and you are good to go.
Looking on our own turf, the Customer Namespace, well… it somewhat remembers me the 300 movie…
– The spartan guys?!
– No, the Immortals. From outside it looks outstanding, powerful, but is simply defeated by a few guys well trained and coordinated.
Our data models are (prone to be) systematically ignored and almost no one feel bad about it. If you do a where-usage in the top 5 Z application tables used in your system and find that at least one have more than 5 different blocks that use a INSERT/MODIFY/UPDATE statement to change table data, you should start to feel bad about it right now.
This same problem is generally followed up by another: code duplication. Since tables updates are done directly in application code instead of a central point, all checks necessary to guarantee data consistency is repeated in multiple points. If you need to add one additional check, you have to repeat this check in all those points, or you are introducing a silent bug that may be only detected weeks or months later that went into production when you are confronted with inconsistent data.
Business operations is functional, but what sustains it is somewhat fragile and requires more time than really needed to keep things working in a shiny state. One way that we can do it better is properly using all the power of packages.
What is package?
Baby don’t overlook me, you must use me, much more.
Package is a container to group objects (really) related in some way, and can be nested to make a hierarchy of related things. You don’t just throw your clothes randomly into a wardrobe, you keep them organized because life teached you that is easier to find something in that way. Code have the same principle, you have to organize those boxes and name them properly. As your codebase grows, more packages are needed to keep them organized (in hierarchies).
The concept is as simple as that, a way to organize your source code (and all other development objects, ABAP ties them into a package). But why we have this mess into code organization?
- Its concept is simply unknown by a considerable part of ABAP Developers, because it isn’t teached in basics. If you never programmed in another language that uses packages, you just assume that those plain few packages that you see on system, created in late 90’s and early 2000’s, are the correct way to use packages, because 20 years passed and no one changed or questioned it.
- There are various types of packages in ABAP, terminologies along the time like client/server, which overcomplicated a simple thing for beginners when they search information in Help pages.
- Help pages itself wasn’t nicely as today, giving only a brief explanation of package purpose and pointing you to inaccessible links for outsiders, like this one from a doc made ten years ago.
Not a good impression at first sight, but don’t run away yet, stick a bit more. You already paid for this ABAP trip, so let’s make it enjoyable. Do a rollback in those statements and start fresh again.
We want to organize, we want to make it easier to find things, we want to everyone respect and comply with data models. How packages can help me in that? Another ally join the fight: the almighty Package Interface.
Package Interface… what?
Package itself group related things, but don’t differentiate what is a internal component and what is intended to be reused. That role is done by Package Interfaces, which lists what things from that package are public (intended to reuse); not finding a object in that list means that you shouldn’t be use it outside that package. One should look at it as a contract between developers:
You should only use what I told because I will always ensure that they’ll have the same functional behaviour, even when I must to do some major changes in my internal components. You can’t blame me if you don’t fulfill our contract and something become broken on your side.
This is the same principle of designing and publishing an API, indeed our reusable code is a internal API for our system code.
This could even be checked and enforced by workbench tools, but…
Package Check: Drawbacks
Package Check is off by default
Yes, you read that right: it’s not on by default. Package checks do nothing while this check is turned off. No sorcery is required to activate, just two steps:
While it is harmless to activate it, it is strongly advised to talk with our development leader or customer IT technical representative before activating it in your work system.
This is entirely optional as it only eases to check the code compliance that leads to a better codebase. But you can benefit from packages interface even with check turned off, but will be more like a verbal agreement.
You still need to write use access to comply with Package Check
This is one thing that overcomplicate packages in ABAP: if you want to use a reusable object from a package in a code contained in another package, you must add the package interface to use access list.
This access list is one way to manage obsolete code deprecation and decomissioning. Even reusable code have a lifespan, because they can be improved so much that a new version of it is created, and you need to give time to everyone transition to the new reusable code.
Again, this is optional and only required if you are going to turn on Package Checks.
Let’s review it all with a example
I want something else to get me through this semi-charmed kind of ABAP…
Our example consists in (re-)create a simplified Business Partner Model. If you jump started your reading onto this part: shame on you. Read it from start and enjoy some sci-fiction (Did you know Code inspector configuration TCode is
Our BP model is designed with only one table, and simply stores BP Number and its name. To guarantee consistency, a lock object is also created. Our design model it as a class and this class is the only intended object to be used by outside world (packages).
Step 1: Organize everything related into a (encapsulated) package
Create package is easy as create a class/report: TCodes
SE80 or in Eclipse ADT itself.
We need to tell that this package is encapsulated, that only objects described in Package Interface should be used by others. If you created in Eclipse ADT, you need to edit package and mark this flag, there is no way (until now) to do that while creating.
The table, lock object and class are also created in this package, just skipping how they are created.
Step 2: Create a Package Interface and spread the word to the world
Also another step easy to do, just create the package interface and add objects to it.
The UI to add objects to package interface could be better, because it required to fill fields in a more technical way.
You can find that information in Object Directory Entry.
After adding objects to interface, save it and everything is ready.
Our rip-off Business Partner is designed to be manipulated only by
ZCL_BUSINESS_PARTNER class. All of its internal components, like database table and enqueue object should never be used outside this class, because our class handles them. If is required to extend this model, like make it replicate to another system, I could trigger that logic on
SAVE method from this class and everyone who handle this data with this class will benefit from this improvement.
Package Check: an ally to discover what code is trepassing our interfaces
All our efforts will be all in vain if no one respects the game rule. Package check
A development was delegated to developer who had fear to fight against empire. The development commander first task was to create a package for this development and give use access to our Business Partner API.
The mischievous developer wrote the code below, which does a direct select on a table not public visible by package interface.
Our commander, in a routine check, found this with Package Check, alerting a problem a potential problem in our base.
The responsible for this code was found and conducted to an interrogation room.
– Bro, WTF?
– I did what this spec told me: a select in a table…
– No no no no! Don’t be too literal with what is written on spec. Try this way instead…
Change your coding workflow
The next time a development requires you to read or change data in a specific table, you first task is to identify what package that table belongs and verify if there is a function or class declared on its package interface that directly manipulate that table.
In a sci-fi world that everyone complies to packages interfaces, not finding a reusable object for changing data means one thing only: it is not supposed that you change data in that table by direct means (i.e. the requirement is wrong). The Package Interface
But remember, what as sci-fi in the past is now reality.
Stay tuned for more instructions to win this war. Next episode is about some topics of documentation and how it can gear up your development speed.
Spoiler alert: Documentation is much more than a text document, even a code can be a documentation.
Well, I allready gave a comment in the prologue: https://blogs.sap.com/2019/06/03/code-less-reuse-more-rebels-rejoin/#comment-475300 , but again here: nice read, thanks for sharing!
I'm a little surpised that there is so little reaction here?! (This ist the very first comment, only ~500 views as of now) or are these common stats in todays SAP community?
Happened to read this while I chanced upon the 'Blogs of Sep 2019' and I am happy that I read this... this topic to so close to my heart and has generated so many WTFs !!!
I am definitely gonna watch this space for more to come and I will try to make this popular in my network !!!
The actual reason the packages are ignored most of the times is because in ABAP they are more or less useless
Normally packages are serving as a namespaces - they are allowing you to have that AbstractStrategyFactory in multiple places. Not in ABAP though! In abap you will have zcl_pr1_pr2_abstr_str_fact and I am not even sure if I went over 30 character limit.
This Pr1_pr2 can very easily be a part of the package pr1_pr2 - but essentially it does not really add much
the package incapsulation is a nice feature of course - but it sometimes backfires to the code of SAP itself! I have seen several times in the standard code that the code from one package is accessing the private class of another package by just generating it dynamically instead of statically. (something like data aaa type ref to object. Create object aaa type 'here_is_my_class_name_as_string')
Yeah, ABAP "Global namespace" and 30 characters limit sure are a [redacted, use your imagination] but we can't do much... backwards compatibility locks out any chance to have any improvement on that. I also feel this pain.
The second part tough I have to disagree: the problem are not the packages, but the developers that are are playing against the rules. They should use only elements from Package Interface, since Standard PIFs were until recently solely focused for their Internal Developments (in a near future also for Customers' developments). If one part don't want to talk with the other and discuss to find a solution which could be:
then former one must be held responsible for any problems that arise.
Regarding the namespace - I could never understood why it is such an issue for SAP to add a flag "package acts as namespace" in the package definition. All your old packages will work as before and all your new packages will be enabled to encapsulate the names inside - no backward compatibility issue so far.
I agree with you that package interface is nice feature. But it has its drawbacks unfortunately, as can be observed in the code from SAP itself...