Branching = Hard
A while ago, Christian Drumm, Fred Verheul and I had a “tweetscussion” which Christian already summarized in yesterday’s blog Question: What System Landscapes Setup to use for Add On Development?. While trying to come up with an answer suitable for the article, more and more details came to my mind, so I decided to follow up the discussion with a blog or two of my own. For now, I’d like to address the topic of the “missing branching support” in ABAP.
Branching support can be quite tricky even if you only consider source code and related files. Actually it’s not the branching that is hard, it’s the merge and associated cleanup operations, but most of the associated problems have either been solved or at least automated to a degree that most developers can use them. Well, sort of.
(xkcd #1597 by Randall Munroe, published under the Creative Commons Attribution-NonCommercial 2.5 License)
For the average non-ABAP project, you don’t actually run the code from any branch of your VCS/RCS directly. At the very least, you have to check the code out, perhaps compile it into some binary and only then run it locally and/or deploy it to a server installation. This holds true even for developers running the software – even if you don’t consider deploying a .war/.ear file to the production environment, you need an application server instance running locally just to try out the application. And apparently, more frequently than not, this process can be a pain in the a…natomy.
The ABAP environment is fundamentally different in a few aspects:
- The code is compiled and executed from the very same repository it is stored in. There is no separate compilation or deployment step required before running a changed version of the code. (Activation doesn’t count in this case for reasons I won’t describe in detail here.) Since there is no explicit compilation, linking or deployment process, the steps that usually take place in such a process either have to be run at a different point in time (which is the case for the load/byte-code compilation), or they don’t happen at all. Linking binaries and resolving library references for example just doesn’t happen because ABAP does not have a concept similar to an object file or a shared binary library.
- The code is always run centrally since no local execution environment exists. The support for developing on different branches of the code that you trivially get when each developer has a separate runtime installation on their local machine isn’t possible that way – some additional precautions would need to be taken to allow for multiple versions of ABAP programs to coexist in a system.
Let’s for a moment imagine there actually was a way to create an alternative version, a branch, of an ABAP class, and have both the original version and the branched version available at the same time. Obviously, you would need to somehow refer to the different versions. In a non-ABAP project, that happens by selecting the different branches when checking out the working copy. Since you don’t check out anything in ABAP, we would need a different approach. The first thing that probably comes to mind would be to specify the version when referring to the class in the code. This would be a bad idea – not only would it add a lot of clutter to the code, but it also would make switching to a new version of a “library” an arduous task of searching and replacing the references in the code. So how about some kind of higher-level grouping, e. g. “Package ABC Version 2 requires Package DEF Version 3”? While this approach would make the operational handling of the relations a bit easier, it wouldn’t change another fundamental problem. Let’s assume that your package currently requires two frameworks A and B in version 1, and framework B version 1 in turn requires framework A in version 1. Now let’s assume that there’s an improved version 2 of framework A, and the developer of framework B decides to switch to that version for some reason. Through no fault of your own, a conflict appears: you need framework A version 1 and version 2 at the same time – which is not really feasible. Welcome to dependency hell. There are ways to work around this issue (after all, the rest of the world does cope somehow), but it adds another level of complexity. And unfortunately, we’ve only just scratched the surface.
One statement I keep repeating frequently in discussions about branching support for ABAP is to remember that “ABAP is way more than code”. Let’s take a simple example: A class has a getter method that returns some description, and for no particular reason, that description is a 60-character text field that is typed using a data element and a domain. For some reason, it is decided that the description needs to support texts that are longer than 60 characters, and since the discussion about the new maximum end doesn’t appear to converge in the near future, you decide to change the return type to a string by changing or replacing the domain. If you did this within a version, you’d probably end up breaking some calling classes since you now return a string where they only expect a fixed-length character field – so you create a new version of your package and make sure that you cover all the usage cases of the getter you just modified. However, it might have escaped your attention that that particular data element was also used in a data structure. Even though you didn’t touch that data structure, you changed it implicitly by changing one of the contained data elements. So, through some convoluted mechanism, the system would have to detect that situation and also create a new version of the data structure. Possible, but complex and probably rather costly.
Now let’s take this one step further and assume that the structure was included in a transparent database table – and you can immediately see where this is leading. You would need two different schema versions of the database table that are accessible at the same time and that could be used interchangeably. Implementing that would be no easy task even for simple field changes, let alone more complex structural changes. And even if you managed to accomplish this for database tables, you would need to support different versions of authorization objects, screens and just about any other object type that can be referred from coding or that refers to coding.
From my point of view, branching within an ABAP system isn’t going to happen – at least not in the near-term future. Support for concurrent branches was not taken into consideration when the system was designed, and one would have to take apart the entire system and re-engineer it from the bottom up, probably breaking backwards compatibility in several places and introducing a myriad of possible bugs. The only option that we are left with is to use multiple systems – and indeed, since that option has been around practically since the beginning (even though it has become affordable only recently), there are a number of ways to structure a landscape of development systems. However, since this wall of text has already reached a considerable height,that topic will have to wait for another article.