BAdI implementation good practices
In this article I would like to discuss some of my thoughts and conclusions you can find useful and implement in BAdI. I will point out things I worked out and noticed during my work. I would also like to encourage you to share your thoughts in the comment section below.
It’s an object
I have seen many BADi implementations and many times I had an impression that the only thing people do is copy-paste code from user exits and wrap it with methods in classes. Let’s not forget BAdI is an interface implemented in class, so we can take full advantage of ABAP OO!
CONSTRUCTORs and class attributes
Lots of our enhancements need to reach database to fetch some additional data or our custom Z-tables with mapping. Let’s imagine that our implemented method is called per each record in a loop (which is quite common). If you implement select statement in this method you will perform multiple calls which will cause unnecessary traffic between application server and database. When you know that table you are going to use is not enormous – select data in class constructor/constructor only once and perform reads only.
CLASS zcl_implementation DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_badi_interface . CLASS-METHODS class_constructor . PROTECTED SECTION. PRIVATE SECTION. CLASS-DATA: _mt_ztable TYPE TABLE OF ztable WITH KEY zkey. ENDCLASS. CLASS zcl_implementation IMPLEMENTATION. METHOD class_constructor. SELECT * FROM ztable INTO TABLE _mt_ztable. ENDMETHOD. METHOD if_badi_interface~process_line. ASSIGN _mt_ztable[ zkey = iv_key ] TO FIELD-SYMBOL(<ls_ztable>). IF sy-subrc = 0. ... ENDIF. ENDMETHOD. ENDCLASS.
In case of class constructor _mt_ztable will be accessible for all instances of your class in program run, so database traffic is significantly decreased. You could also split this data in instance constructor.
What if table is really big and reading it to internal memory is not an option? You can buffer it in attributes:
METHOD if_badi_interface~process_line. ASSIGN _mt_ztable[ zkey = iv_key ] TO FIELD-SYMBOL(<ls_ztable>). IF sy-subrc = 0. ... ELSE. SELECT SINGLE * FROM ztable INTO @DATA(ls_ztable) WHERE zkey = @iv_key. IF sy-subrc = 0. ... APPEND ls_ztable TO _mt_ztable. ENDIF. ENDIF. ENDMETHOD.
Many interfaces have INIT method. In many cases this is also a good place to fetch your mapping data.
This is really obvious, but we’ve all seen too many unreadable methods with hundreds of lines of code. Wrap your code with methods! It is much easier to do in class than in standard user exits. You can create as many private methods as you want and hide some complex logic there. It is even more useful when you need the same logic across different methods of your BADi implementetion.
In classic user exits when there were multiple different cases you were doomed for CASE – ENDCASE or lots of IFs. If BADi can be filtered – use it. You can implement different classes for different cases which separates logic and makes code easier to read and maintain. If you create classes for different cases with different mappings etc. you can use instance constructor to keep relevant data as attribute.
New ABAP 7.52 syntax
In many, many cases signatures of methods contain internal tables. In the old days in order to fetch data from database you would have to use SELECT SINGLE inside a loop or use FOR ALL ENTRIES. With ABAP 7.52 it is possible to perform selects from internal table which has huge utility in our case.
This great blog gives an insight into performance of two statements: https://blogs.sap.com/2017/11/13/the-performance-of-open-sql-as-in-abap-7.52/
Official documentation: https://help.sap.com/doc/abapdocu_752_index_htm/7.52/en-US/abapselect_itab.htm
Important point to note – you can use only one internal table in a select statement. What’s more, internal table cannot have a header line.
What are your thoughts?
The above are my ideas how to implement BADis more effectively and smoothly. What are yours? Do you know some nice practices and tricks?
Luckily I am working on BADI’S and I got Pop up of your blog.
Really it’s a wonderful information about BADI’s.
It will help many ABAP’rs.
Thanks for sharing.
One important point:
There are many BAdIs which include multiple methods for one flow (e.g. process_header, process_item, etc.). However, it isn't guaranteed that the same BAdI instance will be used for all calls.
You have to first check the "Instance Creation Mode" attribute in the BAdI definition.
Thanks for this valuable note! That's why class attributes can be so useful 🙂
This is a good suggestion correct.
But as said by Shai Sinai yes there could be issues with the instantiation. I guess you are recommending to use the Singleton Design Pattern here. Have to be very careful in using this pattern in creating global classes, specially in this scenario for BADI's as it could cause data issues.
But as you have said, I also recommend to use classes, probably utility classes to handle all types of SAP enhancements. It would be really good for easy identification of any custom enhancements as well.
Thanks for your comment! I wasn't thinking about singleton - as you have mantioned it may cause problems. I rather suggested to use all the honey that OO provides which are static/instance attributes in order to reduce database traffic 🙂
The blog has been removed. JFYI.