Last year, our company's BW team approached our software architecture team because they were having issues with their current, standard solution of implementing the customer exit that allows for enhancements to global variables in BW reporting. The function module was growing large, unmaintainable, and hard to control and coordinate between developers. After some design sessions, we were able to provide them with a simplified solution that is still being used today, even in their BI 7.0 implementation.
The technical name of the enhancement is RSR00001 using function module EXIT_SAPLRRS0_001. This enhancement allows for a developer to populate or check BW reporting variable values programmatically using ABAP. You can read the SAP documentation here. The example code that is provided in the documentation and that is considered standard is as follows:
This example works fine if the number of customer exit variables that you implement remains small. However, in our BW implementation, we currently have over 350 custom variables. You can imagine how large and unmaintainable the code started to become.
Not only was the code ugly and hard to maintain, but the biggest issue was trying to coordinate parallel development efforts between programmers. If developer A, we will call him Joe Snuffy, was currently developing a BW report that required a customer exit variable, then developer B, we will call her Jane Tentpeg, had to wait for Joe to not only finish his development and release his transport, but hopefully test and move his changes all the way to production.
This scenario creates productivity problems allowing only one developer to work at a time, but if you don't test and move to production fast enough, it can also cause untested code to make it into production. I know, I know, most of you are saying "What? Every time I move stuff to my test environment, the functional and QA testers are always right on the ball with instant testing and feedback." Well not everyone lives in your perfect, non-existing world, so let's revisit Joe Snuffy and Jane Tentpeg for a moment. Joe does his development and moves to test. Like every sweet, innocent developer, he waits patiently for feedback, issues, or just praise on a job well done (hey, just let me dream a little). In the meantime, Jane starts on her development. There is no way for her to know there is a pending development waiting for testing in a different environment, so she puts her headphones in and starts rocking on her BW variables. Jane is an excellent developer, so she knocks her task out in a day and moves her development to test immediately. The next day, Jane's testers praise her and give her the OK to move to production. Well, as you know, since both developments are included in the user exit code, Joe's untested changes now get moved to production along with Jane's.
You may be thinking that this isn't that big of a deal since each person's variable code should be self contained in it's nice little WHEN statement within the CASE I_VNAM statement; well, you may or may not be correct. Let's have a look at what happened to Joe and Jane. In Joe's code, he uses a newly created data type that hasn't made it into production yet. Now we have a problem that can cause every BW report ran in production to do our favorite thing, cause a core dump due to a syntax error. Oh yeah, good times are being had now that we have brought most of our reporting and analysis down to it's knees. While everyone frantically tries to reverse the damage caused by that last transport, the question that buzzes in the air is "who's fault is this and who do we blame?" Now poor Joe and Jane both get scolded by management and ridiculed by colleagues at lunch time, but in reality, they really didn't do anything wrong.
You may think this is an unlikely scenario, but it has happened to us enough times that our BW core team has now been assigned the responsibility of coordinating, policing, and monitoring all current developments to this user exit. Now in summary, we have created all these problems:
- Ugly code that is hard to read and maintain
- Slow development from limitations of sequential development
- Highly paid people now in charge of babysitting and policing a function module
- Added lines of communication and extra process causing even more loss of productivity
- Potential shutdown of reporting system in a production environment!
Don't fret; there is a solution to our problem. With a little white board discussion and object oriented ingenuity, our small team (Dan McWeeney, Ryan Quackenboss, Phil Young, and myself) came up with a pretty sweet little solution that will reduce your user exit to under 30 lines of code. Yep you heard me right, the simpleBWvariable engine will:
- minimize the code, with no changes required to the user exit itself
- eliminate the need for monitoring and policing of the function module
- allow developers to do multiple developments at the same time
- remove the risk of all reporting in the production system going down due to inadvertent errors
All the code for simpleBWvariables is available for free download, so I will only show some of necessary code needed to install. You will probably want to add the user exit code manually, especially if you are currently using this user exit and want to incorporate this solution with your existing one. I am going to assume you have already created and activated an enhancement project for this user exit.
- Download the simpleBWvariables nugget, import via SAPlink, and activate all necessary objects. You will also need the DDic SAPlink plugin for the table and table type. A link to download plugins can be found on the SAPlink project page.
Objects included in the nugget are:
- Class: ZCL_BW_VARIABLE_FACTORY
- Class: ZCL_BW_VARIABLE
- Class: ZCL_BWVAR_EXAMPLE
- Table: ZBW_VARIABLES
- Table type: ZRSDD_EXIT_RANGE
- Include: ZXRSRTOP_COPY - copy of code to be manually inserted into user exit include ZXRSRTOP
- Include: ZXRSRU01_COPY - copy of code to be manually inserted into user exit include ZXRSRU01
- Go to se37 and display function module 'EXIT_SAPLRRS0_001'.
- We need to add the code from ZXRSRTOP_COPY listed below to the global data section of your user exit. Be sure not to overwrite any existing code that someone has already added for existing variables.
Goto->Global Data->INCLUDE zxrsrtop->add following code
- Now add the code from ZXRSRU01_COPY to the main include ZXRSRU01 for your user exit. Again, be sure not to overwrite existing code. As you can see, we have added the project code to the "when others" section of the case statement. This will allow you to implement simpleBWvariables from this point forward while leaving your existing variables alone.
- Save and activate
Now everything is ready to hand over to your developers. Give them the developer documentation and they should be on their merry way. All documentation can be found on the project wiki. Basically, all they will need to do is make a copy of the included sample class ZCL_BWVAR_EXAMPLE. After the class is copied, they just need to change two methods of their newly created class. First, the constructor method requires a quick change to one line of code to tell it which variable the class implements. Second, the method 'GET_VALUES' contains the actual code to populate the variables.
Once the class is changed and activated, you can now run your reports with the new variable. No additional changes to the user exit are needed. The variable class will even register itself the next time the user exit is executed. How's that for simple?
Well, to verify the simplicity, we gave the developer documentation to a developer that had minimal experience with ABAP objects, and they were able to create and run their new variable with no problems. Now that no change to the user exit is needed and each developer creates their own class containing their own code, variables can be created simultaneously with no need to coordinate transports. Once theirs is tested, the class is moved to production independent of other developments. If there is a syntax error or some other surprise in the newly created class, it will only cause issues with the reports using this variable instead of causing all reporting to come crashing down.
By using some classic object oriented principles, the design is quite simple, yet very powerful. We hope you find this project useful. Please feel free to give us feedback or just leave us a quick comment to let us know if you have found the solution somewhat valuable.