Personal Insights
find names for classes and methods
Thanks to the “Clean ABAP” style guide I think a lot more about the maintainability of my source code. A particularly important point in this context is readability.
In the style guide many recommendations are made to improve the readability. It’s about the order and the combination, how many statements you should place in one line and more. And there is a recommendation to use descriptive names.
I find the topic very important. It can be easy to follow the idea of an application or difficult. That often depends on the terms.
In contrast to the ABAP syntax, the names of variables, classes and methods are “only” limited in length, the permitted characters and their permitted position. How they are finally called decides the developer. Hence many names and term combinations quickly emerge and they must be understood in the overall context of the application.
Example
The following is a small example to illustrate the impact of class and method names on readability. It’s designed under “laboratory condition“. Here are some key points:
- A report is needed that displays sales orders from the Sales and Distribution module (SD) as list.
- The list should be displayed by ABAP List Viewer (ALV).
- At the moment there are just a few fields from table VBAK needed.
- Classes and methods should have English names.
Technically, that can be solved in different ways. For example with ABAP Core Data Services (CDS) and CDS based ALV or with SELECT-statement on tables and “classic” ALV (object-oriented or function module REUSE_ALV_GRID_DISPLAY_LVC) or a mix. For the example we use SELECT-statement on table VBAK and “classic” ALV.
First approach
We develop a single class called ZCL_LIST with two methods called SELECT and SHOW. All source code is implemented in this class.
What should I say? The names of the class and the methods reveal almost nothing about the context.
How to do it better? According to the style guide, it is recommended to choose terms from theย solution domain or problem domain. In our example, business terms increase readability. Here are some ideas how to find them:
- Check the concept if it’s available. The terms used there can be good clues.
- Check help.sap.com.
- If you identify one or more business object types that belongs to your development, try transaction BAPI. Check the terms that are used in the associated documentation, function modules and descriptions.
- Try SAPterm via transaction STERM or online.
- If you identify one or more important tables/data types, check the documentation in English.
- If you identify an important data element, check the default component name.
- Log in with Language “EN” (English) instead of your native language. Then open the business transaction you know from your daily work and check the terms.
Second approach
Now with terms from the solution domain equipped we can choose a different approach. We develop a class named ZCL_SALES_ORDERS_LIST with two methods called SELECT_SALES_ORDERS and SHOW_ALV.
That’s already more informative. Also conceivable would be SELECT_SALES_ORDERS_FROM_DB or READ_SALES_ORDERS or READ_SALES_ORDERS_FROM_DB.
Third approach
The first and second approaches violate the “separation of concerns (SoC)” design principle because our class ZCL_SALES_ORDERS_LIST has too many tasks like reading from database table and displaying data.
That may be ok for a small report. But if new requirements/features are added, we quickly create an inflexible monolith. In my experience, these requirements arise very fast. Especially if the list is used productively ๐ To avoid the creation of a monolith, we could use three classes:
- ZCL_SALES_ORDERS_LIST
- ZCL_SALES_ORDERS_PROVIDER (or ZCL_SALES_ORDERS_READER)
- ZCL_SALES_ORDERS_ALV
The class ZCL_SALES_ORDERS_LIST uses the class ZCL_SALES_ORDERS_PROVIDER to select the sales orders and then outputs them via class ZCL_SALES_ORDERS_ALV. Interestingly enough, the use of specialized classes also has the advantage that the class name becomes more expressive and thus contributes more to understanding.
If we previously had ZCL_SALES_ORDERS_LIST->SELECT_SALES_ORDERS, we can now avoid repeating the term SALES_ORDERS in the method name. So we get ZCL_SALES_ORDERS_PROVIDER->SELECT.
I would prefer the name SELECT if we use the JOIN addition with our SELECT-statement to read header and position data of sales orders at once. Something like SELECT_HEADERS_AND_POSITIONS is certainly ok, too.
Otherwise, specialized methods such as READ_HEADER or READ_POSITIONS are recommended. Perhaps with an addition like FROM_DB.
Ok, that’s all for now – these were some thoughts on the subject of class and method names. As already described, there are countless approaches. What do you think about?
Best regards and thanks for reading
Michael
I, personally, would prefer the third option (composition), but with a small tweak. I would encapsulate the data selection & the list output functions in "local" classes -
I have started using "local" (helper) classes not too long ago. I think they can be useful if the functionality you want to encapsulate in these classes are too specific to the current class (in this case ZCL_SALES_ORDERS_LIST)
The key idea to understand here is "separation-of-concerns". The implementation details can differ.
BR Suhas
PS - Thanks for the blog. Blogs like this will only make developers embrace the clean coding principles!
Thanks for your input ๐ Especially with small reportings based on ALVs I also use local classes from time to time. That's because their content is too specific. As a result, it cannot be reused. So it makes no sense for me to create one or more global classes.
Basically, the idea of a common global class used by many applications is very good. In practice, the coordination of the requirements for this class between different developers is difficult. Even more difficult when working with external developers.
Love this blog.ย I missed the GitHub download before now.ย (I'm downloading it now.)
I also loved the peak into your reasoning behind which method to use.ย I often go back and fourth in my mind.ย Should I split this out? Will anyone find it, if I do....
Thank you!
Michelle
This is a sign that you are interested in your work because you think about and care if it's ok
Hi Michael, naming is always a "big" topic... ๐
Or as Uncle Bob said:
IMHO you mix two different issues: Naming and design. The question if you should use a data access object for data selection does have nothing to do with naming.
You can use precise words to show the intention behind a method.
E.g. READ always implicates an "expansive" access (Read from data base or call to another system). GET inidicates that there is no expensive action behind it.
Of course there should be a broad agreement with your colleagues and common sense what the meaning behind some key words is.
Often the naming must be adapted as the program evolves. This might be the case if - in your case - the naming ORDERS is exact enough at the beginning. But later on you might distinguish between OPEN ORDERS, FINISHED ORDERS and OVERDUE ORDERS or you will have to mark special ORDERS with a special order type or orders of relevant customers or ....
I still love the approach of Paul Hardy who tries to make a program really readable like:
I always struggle if there are some methods that should be grouped be naming.
Normally I would use the naming <action>_<object> like READ_ORDERS or DISPLAY_DATA. But if there are more of these methods which refer to the same object, I tend to rename them to
Then it is easier to identify which operations there are for an object.
btw: READ_POSITION is wrong IMHO and should be named READ_ITEMS... ๐
Hi Enno. Thanks for your input. In your comment, there are so many points and thoughts I have to think about. I will spend some time on the approach of Paul Hardy. That looks pretty good.
I'm not quite at Paul's level of readability, but I have replaced:
with
Reason being, I keep forgetting the NOT in the sy-subrc check (or putting it in when the logic is reversed), and it stops my code working... I do also have a method it_was_found for sy-subrc IS INITIAL.
On the subject of clean code, I've recently started replacing:
Where each comment is an explanation of what's going on in the next section, with:
where each method is named similarly to the comment. It's a quick refactor, it's easy to do, uses fewer lines of code, and makes the code much more clear, in my opinion.
Replacing comments with methods is also very good. This really increases readability. Especially in connection with the IF statement.
Choose names with care. Indeed:
Anyway...
I'd just add, if you define your class public methods wrt an interface, and use interface references instead of class references in the consuming code, then it makes it much easier to write ABAP Unit Tests, using injection.