Technical Articles
Proof of Concept for ABAP libraries and library management system (abaplib)
Introduction
There is something that’s been bugging me a lot about the hottest thing happening in ABAP right now – the RESTful Application Programming Model, ABAP RAP for short. Why do we need to modify the language itself to achieve such functionality?
I can look past the CDS – we can think of them as sort of metadata files that define the structure of our service. That’s okay. But what is the point of something like an Entity Manipulation Language? Here’s an example of what I mean (image from Yogesh Vijay’s blog post):
MODIFY ENTITIES – CREATE
Why would you want in any way for statements like “MODIFY ENTITIES”, “MAPPED”, “REPORTED”, etc. to be a part of the core language? The core language should, in my opinion, be kept as simple as possible. And any additional functionalities should be provided by libraries/packages/APIs/etc. This is the approach that developers take in pretty much all popular modern languages, e.g., Java, Python, JavaScript, and others. If these developers are able to provide additional functionality without extending the language itself, then ABAP developers must be able to do so too.
Unfortunately, we don’t have a library management system (LMS) in ABAP. Specifically for my point of the ABAP RAP, I’m pretty sure that the model can be made to work even right now, without such a system. By using a global class API, such as the XCO library, this should be possible. But this is what got me thinking about this sad fact that we don’t have an LMS in ABAP.
So, I started wondering whether this could be done with the current state of the language. I actually believe the answer is yes. And this is the idea of this blog post – to demonstrate the technical feasibility of such thing. Keep in mind a few things – there is a significant number of points that I think should work in theory, but I haven’t proven this in practice. Furthermore, this is an idea I got and developed for a few hours, so there could be many points which could be implemented in a much more elegant and/or efficient way. Lastly, none of the mentioned technologies (e.g., abaplib.com, abaplib client) exist yet, they are purely hypothetical. With that in mind, let’s dive in my idea.
abaplib.com
We will start with the place where the ABAP libraries would be hosted. It is a similar idea to the Python Package Index (pypi.org). It would be a software repository. Firstly, it can be used from your browser to explore libraries (pypi analog example – the PyOData project). Additionally, it could be used directly from the SAP system through a client API that would allow the installation of a library. More on this later.
Most importantly, abaplib.com keeps old versions of libraries too. This is very important, because some project may depend on a library’s specific version. Again, this is similar to what happens with pypi, through its release history functionality.
Lastly, each library will have its GUID (globally unique identifier). It must be a short one, not more than 4-5 characters due to ABAP’s very restrictive limit of 30 characters per class name. More on this later.
ABAP library specification
For the idea to work, an ABAP library must follow this structure:
1. Class ZCL_{library name}
- This class serves as the entry point to the library;
- It must NOT be final, so that it can be inherited;
- The class must have only static methods;
- These static methods can access anything else inside the library;
2. Anything else the library needs – classes, interfaces, subpackages
- These should only be directly accessed through the class from point 1.
Example:
Library abapmath ZCL_ABAPMATH ZCL_HELPER
The reasons for the structure will become clear in the next section.
abaplib Client
The client would be installed on your ABAP system using abapGit. It would have some interface (GUI/UI5/REST/CLI-like, possibly all). From this interface, you would be able to download the required libraries for a project.
It would work in the following way:
(1) User inputs their project’s package
(2) Inside this package, the client will create an interface called ZIF_ABAPLIB_{GUID}
- the GUID is randomly generated by the client. It must be unique for the whole system. Also has to be short, 4-5 characters. Again, more on this later.
(3) Inside this interface, the user must define a constant called libraries. It would be a structure, where each column would follow this format:
- {short name for library} TYPE zcl_abaplib=>library VALUE ‘{full library name as specified in abaplib.com}, {version}‘
- Example:
INTERFACE zif_abaplib_a8j7 PUBLIC.
CONSTANTS:
BEGIN OF libraries,
math TYPE zcl_abaplib=>library VALUE 'abapmath, 1.0.0',
END OF libraries.
ENDINTERFACE.
- Example explained: use the (fictional) abapmath library, using an alias for it – ‘math’. Similar in spirit to import numpy as np in python.
- zcl_abaplib=>library is just a wrapper type for string.
(4) On user request, download all dependencies. From user’s perspective, they just point a package (for which steps 1-3 have been completed) and click “download dependencies”. What happens behind the scenes is as follows:
- (a) The zif_abaplib_{GUID}=>libraries constant is read. The GUID is the one generated for this package in step 3.
- (b) For each library, an HTTP request is sent to abaplib.com to download the relevant library and version. The HTTP request would include as query parameter the GUID for the package. Dependencies of the library itself are also downloaded.
- Example HTTP request:
GET https://abaplib.com/library/abapmath/download?version=1-0-0&pguid=a8j7
- (c) The response would be a ZIP with the relevant objects of the library. The abaplib server will return the ZIP with the files named as follows:
- {name}_{package GUID}{library GUID}
- Example:
abapmath-1.0.0-a8j7.zip
Contains files (XML metadata files not shown for simplicity):
ZCL_ABAPMATH_A8J7MB8D.clas.abap ZCL_HELPER_A8J7MB8D.clas.abap
The suffixes will be automatically placed by the server, and the library developer will not have to worry about them.
-
- This is how it is ensured that within the same system, the same library can be installed multiple times (in different packages). The name will be unique due to the use of the package GUID. Also, it will ensure no clashes occur between libraries – for example, if two libraries both have the class ZCL_HELPER inside, their library GUID will take care of this.
- Unfortunately, this means that only about 20 characters will be left for the object’s actual name, but I don’t think there’s any workaround that. Therefore, library developers must be aware of this and never use more than (30 – strlen(package GUID) – strlen(library GUID)) characters.
- (d) abapGit would be used to install the ZIP, in a subpackage named Z_DEPENDENCIES_{package GUID}
- (e) For every class that already exists in the package, the following code is added in its local types:
- CLASS {short name for library} DEFINITION INHERITING FROM ZCL_{library name}_{package GUID}{library GUID}. ENDCLASS.
- This is the entry point class described in the previous section (ABAP library specification).
- Example:
CLASS math DEFINITION INHERITING FROM zcl_abapmath_a8j7mb8d. ENDCLASS.
(5) For every newly created class from here on, step 4.e has to be repeated either manually by user (copy-paste from existing class’ local types), or through the abaplib client.
Usage in user’s code
Let’s continue from now on with our (fictional) abapmath library. We assume it has been downloaded to our system, in the subpackage Z_DEPENDENCIES_A8J7. It offers us a method called floor_sqrt. And that’s all (not the richest library, I know). The method does the following: Given an integer x, find its square root. If x is not a perfect square, then return floor(sqrt(x)). It’s an ABAP implementation of the simple approach described here by GeeksforGeeks.
Since we will be using a library, we don’t really care about the implementation, we just use the abstraction. Still, for completeness sake, here is also the implementation:
CLASS zcl_abapmath_a8j7mb8d DEFINITION PUBLIC CREATE PUBLIC.
PUBLIC SECTION.
CLASS-METHODS:
"! Given an integer x, find its square root. If x is not a perfect square, then return floor(sqrt(x)).
"!
"! @parameter num | Integer number to find the floor root for
"!
"! @parameter result | Floor square root of number
floor_sqrt
IMPORTING num TYPE i
RETURNING VALUE(result) TYPE i.
ENDCLASS.
CLASS zss_abapmath_a8j7 IMPLEMENTATION.
METHOD floor_sqrt.
IF num EQ 0 OR num EQ 1.
result = num.
ELSE.
DATA(i) = 1.
DATA(temp) = 1.
WHILE temp <= num.
i += 1.
temp = i * i.
ENDWHILE.
result = i - 1.
ENDIF.
ENDMETHOD.
ENDCLASS.
Lastly, we have some business logic class. The abaplib client has already generated this code in its local types:
CLASS math DEFINITION INHERITING FROM zcl_abapmath_a8j7mb8d. ENDCLASS.
So, from now on, we can call the abapmath library using math=>{method_name}. Here’s an example:
CLASS zcl_some_bl DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES:
if_oo_adt_classrun.
ENDCLASS.
CLASS zcl_some_bl IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA(my_sqrt) = math=>floor_sqrt( 32 ).
out->write( my_sqrt ).
ENDMETHOD.
ENDCLASS.
We also obviously get access to the library documentation:
Our entry point class can access anything else it needs inside its library, as already discussed. Object creation like this will not be the most elegant (no NEW operator), but can still be achieved using a factory pattern without any problem.
Conclusion
I hope I have managed to convey my idea clearly. In my opinion, almost nothing of what I described should be particularly hard to implement, although it will be time-consuming. Only point 4.e. from the section for the abaplib client may be hard to achieve; but, worst case scenario, there could always be work-arounds.
Also, as I mentioned in the beginning, these ideas might not be the most efficient or elegant. Nevertheless, at least the way I see it, they should lead to a fully functioning library management system for ABAP. I think having something like this is a must. It would open a lot of doors for ABAP and ABAP developers.
I’ll be looking forward towards your comments! I am particularly interested in these points:
- Do you find some issue with my idea – both from technical and business POVs?
- Do you think ABAP should have an LMS?
- Would you use an LMS if it was available?
Thanks for reading!
I sooooo much agree with your sentiment that incorporating EML (and actually almost everything) into the core language is a poor design choice! And IMHO the resulting syntax is terrible.
That said, I haven't yet read the remaining part of your blog post, but I think you might want to take a look at the ABAP package manager, introduced by Sebastian Wolf on Github (see last slide for more links, e.g. a blog post here on SAP Community). I'm not sure what the status is, but contributing might be better than reinventing the wheel.
Fred
Hey, Fred, thanks for your comment!
My main intention with this post is to start a discussion about a package manager in ABAP, and share my personal opinion about EML, which I'm glad you share! The technical idea itself is not too valuable (nor particularly elegant).
I was actually not familiar with apack, took a quick look at the presentation. It looks awesome. I'll be researching it more, and maybe I can indeed contribute to the project (if it's still alive!) 🙂
Best,
Stoyko
APACK hasn't gained that much of traction to be honest, but maybe it simply came too early. 😉 Contributions (both to APACK and the hosting abapGit) are always welcome, so maybe we can join forces here...
Best regards, Sebastian
Hey, Sebastian,
Thanks for chiming in!
After my (very short) research on the topic, I’d say that APACK is a great start. I also went successfully through the demo you’ve provided.
I’m curious, have you had a chance to see this relatively recent comment from Marc Bernard (and the comments that follow)? I found it out during my APACK research (and so after writing my article
). It solves a lot of the issues I am discussing here, such as allowing multiple installations of the same library. Also, proposes the use of central repository, as do I. Which means the user don’t have to provide the git clone link themselves, just the name in the central repository.
Marc also mentions “No more abapgit.xml, no APACK. Whatever they contained or did needs to move into package.json”, but I somewhat disagree with this. Yes, I do believe using a JSON dependency list (manifest) is the more elegant solution, but APACK seems to be doing much more than just creating the manifest.
Instead, IMHO, his comment describes much of what APACK should aim to become. Would you say you agree with this statement?
Best,
Stoyko
Thanks for the link to the comment. I haven't followed the discussions around that recently because of other obligations. So it's nice to see that the idea gains some traction. I still have to think a little bit about it, but maybe I already share some of my half-baked thoughts here. 😉
On the other hand, I don't have any issue if another solution different from APACK is the chosen way to go. The main thing IMHO is that ABAP finally gets a proper package management system for the open source world...
Best regards, Sebastian
Hey, Sebastian,
I am very glad you've shared your thoughts on the matter!
Best,
Stoyko
A relevant link, https://medium.com/@sdboyer/so-you-want-to-write-a-package-manager-4ae9c17d9527
As mentioned in the abapGit thread, renaming can be done, IF making assumptions regarding the code, I feel like there is a lot of examples that does not make up an "abaplib".
In the ABAP world there is a somewhat overlap of CTS and a package manager, CTS stores the finalized developments like a package manager does, and deploys the development up the stack. I.e. the code entry into a SAP landscape would always be the development system?
Git is a good(?) tool for development, and it stores old versions too.
Package managers end up being decentral anyhow, like SAP had their own npm registry(now moved), GitHub provides a npm registry etc., in Deno each dependency is just a URL
just a few cents...
Hey, Lars,
Thanks for your comment and suggestions!
I've taken a quick look on the medium article you've shared. Will read in-depth at a later point, but just to mention here I'm loving the opening that software and people are terrible and nothing will really work for sure 🙂
I very much agree with your point that the git client shouldn't be doing the renaming, but I do also think it must not necessarily happen at build stage. I.e., have an intermediate stage where it happens. Clearly, assumptions must be made due to this, which you also mention.
I don't think this is too bad. But also a possible way to avoid it is to require the library creator to include a metadata file that specifies renaming patterns for any object they have. This will also give library maintaners the option to choose themselves whether different versions of the same library need to also use different database tables, or it's fine if in the same system there's multiple versions of the library, but all re-use the same DB table.
Lastly, and not very related to the package management discussion, I feel like your transpiler project may be the second best thing to happen to ABAP after abapGit. IMO, if it does reach a fully functional stage, and developers can write in their local environment, free from an SAP system, it will be a huge boost to the language and may lead to lots of new libraries being created. And with lots of libraries out there, will also come a much higher motivation for building a package manager. May be it's a chicken-egg problem and the libraries have to come first 🙂
Best,
Stoyko
I'm just working through your concept. I do agree about EML... but I don't agree that a language should be as simple as possible and only extended via libraries. I program in Java and ABAP. I find each approach has its strengths and weaknesses; I wouldn't say either is better. The richness of ABAP gives it a power and sometimes simplicity that Java doesn't possess.
Btw, I'd use the term SUID rather than GUID for a system UID. (As opposed to a Global UID - or Universal UID, UUID).
Hey, Matthew,
Definitely agree that SUID is a more appropriate name!
Also, you raise an interesting point. Do you have a concrete example of where ABAP's richness, as you call it, makes it more powerful and/or simpler than Java?
Best,
Stoyko
Sure.
Internal tables is the obvious one. Sure, you can use ArrayLists/Vectors/Maps etc. but for simplicity and easy of use -Internal tables take some beating.
a real life/live example at https://github.com/abapGit/ajson_mirror, it takes the code from https://github.com/sbcgua/ajson and automatically renames it to ZCL_ABAPGIT_, all possible to run automatically on GitHub actions, or other pipelines
Yeah, as discussed already, from technical perspective it should work without any problems as long as developers follow some naming patterns. At the very least allowing some extra space, to conform with SAP's 30-char limit.
As a side-note, yesterday I was participating in a TDD in Golang training, and felt so liberating to write tests called TestSomeMethodSomeAction without worrying I'll pass 30 chars... and have to call the method TestSmMethSmAct.
Back on topic, for the ajson mirror, I took a quick look, it's very cool you've already implemented the renaming in abaplint, and works beautifully simple with the rename parameter in the apalint.json