Technical Articles
My golden rules of robust programming
I’m always struggling in finding the right way to code, even more after 25 years of ABAPing. So I listen to speeches on youtube, read books about programming style and – last but not least – enjoy discussing the various principles of good programming in this place here.
In this blog post, I’d like to present some of my own “golden” rules in coding ABAP, hoping you will join me writing your own rules into the comments (or busting my rules with your knowledge…)
So, here we go
- Use Model – View – Controller architecture
You never know if your application should run on Fiori tomorrow – so split the data manipulation logic from the presentation using this pattern - Avoid using class attributes
Class attributes are global variables. If you set use them in your methods, your program decreases in legibility. - When using class attributes, access them only in public methods
You can’t always avoid class attribute. In a model that serves a front end, you have to keep your application data in attributes. However, if you are calling methods to manipulate this data, pass everything that’s an attribute as parameter. Your methods remain pure (processing only what’s been passed by parameters) and understandable - Keep methods small
It’s so comfortable to read through a logic that spans only one page on the screen. So, as soon as my method becomes larger, I think about meaningful possibilities to split the logic in more methods. - Isolate database accesses
If you see that you have to read another customizing table in the middle of the logic of your coding, you may think about a small line “select * from tvbur…..” just to get the data. So maybe a method “sales_totals = calculate_totals( sales_documents )” has some SQL statements that a reader of your program would never expect. So I try to put all the DB accesses apart. One good way for this are data provider classes (see https://blogs.sap.com/2017/10/31/the-global-variable-dilemma/). - Use meaningful descriptors
A not-so-long time ago, I used to code things like “lv_matnr1 = get_sup_dum_comp( lv_matnr1 )”. Now I have to maintain these programs – what a mess. Nowadays, I’d write “superior_dummy_material = get_superior_component( component_material )”. I sacrificed the prefixes for more meaningful variable names. - Avoid changing variables
This is a principle I took over from the functional programming paradigm. First, it confused me – aren’t variables made to change them? You’d be amazed how rarely you really have to change variables, and the new declarative additions that came with ABAP 740 are supporting this functional way of coding. The reason for this is of course again legibility. See the little exampleheader_material = order_header-matnr.
headline_text = read_material_description( header_material )
component_:material = order_component-matnr.
component_text = read_material_description( component_material ).instead of
lv_matnr = order_header-matnr.
headline_text = read_material_description( lv_matnr )
lv_matnr = order_component-matnr.
component_text = read_material_description( lv_matnr ).where a variable is being reused.
Best regards
Jörg
Hi Jörg,.
nice summary. As I agree to a lot of your points I struggle a little with two points.
Number 2+3. Why avoid it. When you do have classes designed, why should I avoid class-attributes. Of course, valid point if you just create one class and do everything there, but that is nearly the same than using formroutines or doing nothing of that and have italian spaghetti coding ? and for number three I don't see an advantage to make everything public then...but maybe it's my JAVA-background here...
Number 7. I understand it from a point of view, when there is a variable, which might be declared with something like string / xtring / int… but when I have a variable to just match a datatype (before 7.40) I cannot understand your point. Today why not do it that way
And if it not compatible, do a conv
https://help.sap.com/doc/abapdocu_751_index_htm/7.51/en-US/abenconstructor_expression_conv.htm
The goal is to have "pure" methods - which means that the result of a method depends only on the input you passed. If a method accesses class-attributes, the result depends on the value of this attribute and the functionality is somehow obscured, because the caller does not know the value of the attribute. If you use pure methods instead, you can also relocate them to other classes without problems, they will always work.
Of course, some classes like data models and data providers are designed to provide data in attributes and there you will create them. But it's a good idea to not access them in private methods but to make the caller pass them as parameters. If the caller is public, it should pass the attribute to the private method's parameter.
My example for Number 7 was poor and of course I do it as you suggested in real life.. It was just to illustrate the problems that can occur re-using a variable for different purposes. In fact, ABAP's 740 extensions (value, cond, new...) do help a lot when it comes to avoiding multiple variable assignments.
Hmm, I'm with Florian on this one, some very good tips apart from these.
You write above "the result of a method depends only on the input you passed", in fact your entire first paragraph describes static methods. In this scenario you might as well write function modules.
An abundance of static methods is often a sign that objects aren't modelled as well as they could be. Only methods that are truly static should be static, and those tend to be few.
It's the combination of data and methods that work on the data that make an object.
I'm not referring to static methods. Think of a model class with attributes keeping the data for an interactive application. When data has to be manipulated,, I call a private method that is pure - which means that I pass the attributes as parameters.
Maybe I am misunderstanding something, but what I have seen often is methods that would have no loss of functionality in converting it to a static method. They simply act on the input and produce a result, independent of the object instance they live in. This is usually a sign of a hidden object.
And this is also how I interpret your descriptions, in particular:
Your methods remain pure (processing only what’s been passed by parameters)
If you use pure methods instead, you can also relocate them to other classes without problems, they will always work.
I am genuinely interested if I’ve got it wrong, maybe you could provide an example of what you mean? Good vs. Bad
A crude example of what I mean:
This is a pseudo-static method, having no interaction with the class. It could be made static, or might as well be a standalone function module.
It's difficult to do a short example for this. In refactoring, sometimes you decide to relocate a functional method of a class in order have it available in the caller of the class, because the result of the functionality is used also by the caller.
If the method is pure, you simply copy the method from one class to the other and delete it from the first one. If the method is using class attributes, this is not possible without further code adjustments.
Then you call the method in the caller, memorize the result and pass the result to the called object adding a new parameter...
Rather than getters and setters, I declare the attributes as public read-only, and write setters.
A very brave person. I've been to different places, programmed for quite a while, and still don't have a "strict" set of rules. I guess I try to use MVP where I can. And meaningful names - yes.
Class attributes is not a rule I follow all of the time. There are times I want to set them once and leave them alone. I don't have to pass them in at that point. (My preference) I do try to limit them.
Avoid changing variables. Mmmmm.... Not sure about that one. I'll have to go back and look at my code.
Unit test?! Someday I'll do them all of the time. Someday. Today there just seems like so much to learn and a short amount of time.
Nice blog!
Michelle
A tip. Next time you come across a bug in your code, instead of running the app and debugging, then fixing then running again, try this.
A book that can help do this is Michael Feathers - Working Effectively with Legacy Code (where legacy code = any code not testable by ABAP unit tests), and Meszaros xUnit Test Patterns. I've found both to be invaluable.
Thank you! Just went to buy the book.
Thank you for sharing this with us.
Really useful.
Jorg, thank you for the great post!
I would add to your point #6 on meaningful names: volunteer to help maintain the programming standards manual, with the goal of eliminating unnecessary naming requirements (like your example of the LV_ prefix for any local variable).
Also, I would add a point to encourage code reviews. Robust code is much easier to create when many sets of eyes are looking at the code, not just one. We as developers are much like prose authors: our eyes see what they expect to see. We can miss an obvious flaw simply because we've been staring at that same section of code for two weeks (or more).
The classic proofreading example is:
Our code contains the opportunity to overlook many logical or functional errors and we can miss accounting for all data values very, very easily. Code reviews can be very helpful in finding these errors by someone asking the simple question "what happens if.......".
Another advantage of code reviews is to "spread knowledge" among a development team. We all come to the keyboard with our own experiences of past projects and have our own list of handy function modules and routines we've found or written along the way. Code reviews help share the wealth, as it were, of the experience that exists in every team.
Thanks again, Jorg, for taking the time to share your thoughts with us all!
What coincidence - we are actually on the way to implement code reviewing in our development department - it came up just one day after I wrote this post...
I would love you to elaborate on the bit about not changing variables.
I first heard about this recently when "Uncle Bob" wrote a series of blogs about his "Space War" program, written using "pure" functional programming.
In that program when you blow up some Klingons, the values of the existing variables do not change, but a whole new "world" is created with new variables, the bulk of which have the same values as the variables in the old "world" there are just lower values in the new variables saying how many Klingon ships are still intact.
That seemed very strange to me. I must be missing something really obvious.
In transactional applications you have a bunch of fields which are changed by a user, and often other hidden values get updated (changed) when the end user changes the values in say, a sales order. How does that all tie in with not changing variables?
Do not get me wrong - I want to understand why never changing variables is a good thing. At first glance the "open closed" principle appears similar - change the behaviour of existing code without changing the existing code, which seems impossible but is actually not that difficult and can be done in lots of ways.
I presume that I just need the light bulb to go on in a similar way in regard to why changing variables is Bad Thing....
Cheersy Cheers
Paul
Hello Paul,
in exact terms, the target is referential transparency: code is simpler to reason about. Immutable variables behave more like global constants, they don't hurt as global variables do.
This is one of the tenets of functional programming. Use a chain of pure function calls to transform the original data object by creating new objects. There is no magic, we a lot of new variables to avoid changing the old one, but they are mostly passed as parameter on the call stack and need not be declared explicitly. The function call is the much powerful language element. You can work with recursion and never use loops (shameless plug: try ABAP Scheme).
JNN
In addition to Jacques Nomssi Nzali 's excellent reply, I want to outline that I wrote "avoid" changing variables. Replacing a loop with a recursion is a thing I do rarely because it blows up the code and makes it less understandable. Here's a loop that changes data in a table that I would not replace with some functional construction, because the loop version is straitforward and clear:
But if you look at
I would always prefer
You avoid errors like "forgotten clear" and "use value of a field before it was set" and so on. They are just not possible any m ore
Just for fun, there’s no reason the loop example above can’t be written in a functional manner. Personally I would extract complex statements to enhance readability in any case.
Most people reading would be interested in the overall flow so having a single English-readable statement is easier to read.
That's a nice approach. But still the variable line is being changed in the loop....
Sure, the example was more about the tangential discussion about functional constructs replacing the loop.
But one could probably take this example further and replace the has_sibling element with a functional method. The has_siblings element is technically redundant, so it doesn't need to exist and therefore never needs to change.
If we need a flat table, such as for SALV, then this is generated on demand, at which point you can write out a table containing a has_siblings field. No change needs to take place.
(Note, this is a mostly academic discussion, there is plenty scope for changing variables, but the principle of avoiding it is a good one).
is a while loop really more functional than a normal loop?
Good question!
On the surface, and specifically with such a simple example, they may seem the same. But there's a world of difference.
A loop has a (mostly) static scope.
WHILE is a conditional repetition, and the iterator get_next( ) encapsulates the scope and content. I control both inside the iterator function. The caller doesn't need to know or care whether I'm looping over a table or traversing a tree. Things like AT FIRST, AT NEXT and inserts/deletions/invalidations can all be managed in the iterating object.
e.g. I might update an item in a list in a way that invalidates a previous item. I just reset the current position and the WHILE loop just carries on. It simplifies the body of the loop to the actual function we're performing on the data, making it easier to read and understand.
Well, I’d say this opened a world to me. Thank you!
Hello Jörg,
thanks for sharing your abap best practices in this blog.
Also comments to your blog are very interesting and made me think.
To me the idea of idempotent API calls is known from implementing REST APIs.
From my point of view it is possible to have idempotent calls to an object, given its state is immutable.
In other words, it is possible to have member variables (class attributes) without passing
them via method signature to your own methods and achieving idempotency.
The challenge is how to implement setters and all other methods that will change the state of an object.
One way of doing this, from my experience, is to have the setters to return a new instance of this object to represent and encapsulate the new (changed) state.
You avoid errors like “forgotten clear” and “use value of a field before it was set” and so on. They are just not possible any m ore
Hallelujah.
Thank you for writing this.
N
Well, almost... I still use prefixes for method parameters and type / class definitions - it turned out that without these readability suffers a bit.