Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
hardyp180
Active Contributor
In my prior blogs:-
I talked about the historical background that caused me to want to re-write an application in a modern way, steps I have already taken to try and make custom programs more "portable" between SAP systems, and how I am going about building the new "modern" version of the example application
Next Thursday I give my speech at the Australian SAP user group conference on this subject, so my final blog on this topic will be a recap of that presentation.
In the meantime I shall once again go more or less totally off topic and talk about my experiments with some of the new “hammers” in ECC 6.0
BRF Plus
At my company we have been doing lots of experiments with this lately to try and find out if and when it could add value. The basic idea seems sound enough – it is in effect a souped up version of the IMG, and the idea as I understand it is to try and push more ownership of business rules onto the business i.e. the people who make the rules.
The other day I was trying to implement a complex rule in BRF plus and it was an emotional rollercoaster. I shouted and swore at the BRF workbench, but in the end when I looked at the finished result it looked quite good in that it was clear to an observer how the rule worked, especially with the built in simulation tool.
So, though I quite like it, I have to bring up a list of the negatives. It seems to me that the product is still to all intents and purposes in beta as there are a lot of apparent bugs and OSS notes come out on a very regular basis, and there are lots of blogs from the author on new features and changes as a result of feedback from initial customer implementations.
-          As the workbench runs in a Web Dynpro application, after calling the transaction in the SAP GUI you have to log in with your username and password again. This drives me nuts in PI in which the three parts are clearly designed to work together but you log on to each separately. I imagine people will bring up the mythical “single sign on” to bypass this problem, but why was it designed this way? In BRF plus you sometimes even get the “you are logged on multiple times” warning. Well of course you are – you are logged on in the system where you entered the transaction code and that same system which you have just been forced to re log in to.
-          There are no naming restrictions on the various objects in BRF plus – you can call each object the same name if you want. We have introduced a naming convention where you say what something is e.g. DT_ as a prefix for decision table. We did the same in PI and then that all fell over when SAP renamed all the objects, making our convention meaningless. Going back to BRF+ I have discovered if you name an object TEST then everything falls over.
-          When creating objects the text name is optional, and as far as I can tell when creating rules you can’t add a name at all, though you can for all the other objects. I think it is quite important to give something a meaningful text name as that is what shows up in the overview.
-          The workbench crashes all the time, the screen goes bright white, and you have to close the browser, and then when you go back in, you are locking yourself.
-          Far too many button clicks to enter data. Any ABAP developer will be used to directly entering things, and this seems like pulling teeth.
-          In the simulation scrolling down is agony. You have to press the bottom right hand part of the screen to move down one line, and then the box automatically resizes itself based on the length of the new line, so your cursor is no longer in the bottom right hand corner, it is either to the right or the left. So, you just keep pressing the same key repeatedly to scroll down line by line you have to re-focus the cursor each time
-          Simulation performance is terrible. To be fair when the application runs in ABAP there is no discernible pause.
-          This is going to be very hard to sell to ABAP developers. They will say that everything you see in BRF plus can be done easier and faster in a program using Z tables. That might even be correct, I am keeping an open mind, which is why I am doing these experiments.
Local Class
In my last blog I mentioned I was writing a “pattern” so that I could automatically generate the skeleton of implementations for my local classes, in the same way you can do this for PERFORM routines. This is a bit of a gap in standard SAP, especially when SAP are pushing us to use OO techniques.
Anway Jeroen Verbrugge pointed me to a wiki …
where Rüdiger Plantiko had done something very similar and had developed a useful custom Z class to help with this. I created this Z class in my system ten minutes after reading the wiki.
DATA: lt_source_code TYPE stringtab.

 
READ REPORT ld_program_name INTO lt_source_code.

 
CHECK lt_source_code[] IS NOT INITIAL.

 
TRY.
     
CREATE OBJECT lo_scanner
       
EXPORTING
          it_source
= lt_source_code.
   
CATCH cx_abap_error_analyze.
     
RETURN.
 
ENDTRY.
This is still a work in progress for me, what I want to be able to handle is handling the possibility of multiple class definitions at once
"Make list of class definitions
 
FIELD-SYMBOLS: <ls_statements> TYPE sstmnt.

  lt_statements
= lo_scanner->get_stmnts( 'CLASS' ).

 
LOOP AT lt_statements ASSIGNING <ls_statements>.
   
CHECK lo_scanner->get_first_token( &lt;ls_statements> ) = 'CLASS'.
   
CHECK lo_scanner->get_nth_token(
                                iv_n     = 3
                                 is_stmnt
= &lt;ls_statements> ) = 'DEFINITION'.
    lt_class_name-clsname
= lo_scanner->get_second_token( &lt;ls_statements> ).
   
APPEND lt_class_name.
 
ENDLOOP.

* Call the help-routine.
 
CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST'
   
EXPORTING
      retfield       
= 'CLSNAME'
      dynpprog       
= sy-repid
      dynpnr         
= sy-dynnr
      window_title   
= 'Choose a Local Class'
I also want to have the signature in the implementation as comments. I like this feature in procedural programming, and I think in OO world it helps the casual reader know where a variable has come from.
*&---------------------------------------------------------------------*
*&      METHOD  CHECK_DOCUMENTATION
*&---------------------------------------------------------------------*
* METHOD check_documentation IMPORTING pud_object_type TYPE trobjtype
*                                                                            pud_object_name TYPE sobj_name
*                                                                           puf_show_doco   TYPE char01
*                                                      CHANGING  pcd_subrc       TYPE sy-subrc.
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
* METHOD example.
*
* ENDMETHOD
*
*ENDCLASS.
                    "lcl_test_db_access_class IMPLEMENTATION
Lastly, I want my code to spot if an implementation has already been coded, and if so not create duplicates, but just create skeletons for any missing declarations.
Pragmas
I use these all the time now, see below for an example of when I have a routine which would trigger two separate errors in the extended check. It is a silly example, but the point is clear I hope – before I could only do one pseudo comment.   
Also now you can put a real comment after the pragma e.g. ##needed "because of such and such
Class Based Exceptions
This has been a real struggle to me to see why this is better than what went before. It doesn’t help that most of the documentation says “do this because it is better” and not really say why, at least not in a way I can understand.
The SAP Press Workflow book says an exception class is a message class and the exception texts within the class correspond to messages numbers where you pass in variables e.g. class CX_SY_NO_HANDLER has an exception test “An exception with the type &CLASSNAME& occurred, but was neither handled locally, nor declared in a RAISING clause” and the &CLASSNAME& is filled at runtime with the corresponding attribute of the exception class. So far so good, I can see that analogy, the next step is to try and see why such a class is better than raising messages in the traditional way.
Often people think describing how exception classes work is all you need, as then it will be blindingly obvious how it is better. It isn’t, at least to me.
However I have no doubt that everyone who says this method is better truly believes it, so I went looking on the internet for where this concept came from.
I found an article by Bertrand Meyer from October 1992 which proposed a system or object orientated exceptions almost identical to what SAP now has.
That helped explain things to me.
It would clearly be silly for me to re-iterate everything in that article – you can read it yourself! – but I will try and do a summary of the parts I think relate to ABAP, a language that was somewhat different in 1992 I imagine.
Inside a method you have a series of checks. In his language EIFFEL they were part of the language itself, naturally in ABAP we code such things ourselves.
First you have a precondition a failure of which always indicates a bug and thus needs to throw an exception. This indicates a bug in the caller, so you pass exception up to caller. This is like a BAPI filling up the BAPIRETURN table and then leaving the BAPI function.
The stronger the precondition the more the caller is responsible
For a special case i.e. an acceptable expected situation you handle this by IF statements, as this is not a bug and so no exception should be raised.
At the end of the method is a post condition which translates to “I did what I said I was going to do” the failure of which always indicates a bug and thus needs to throw an exception – this time this indicates a bug in the routine, so you are supposed to handle the exception within the method.
He talks about a “Class Invalidation” – e.g. car has four wheels, the method has removed one, and at end of routine it failed to add one back. So an exception is magically thrown without being in the code. No equivalent there in ABAP I think.
In a subclass – new precondition OR higher level precondition – this makes the precondition weaker, so the routine more responsible
In a subclass – new post condition AND high level post condition – this makes the post condition weaker so the routine more responsible
So, the weaker the precondition and the stronger the post condition the better the job the routine is doing…. If you can think of the behaviour of a method in human terms….
Then he starts talking about exceptions, and the various ways you can respond to a problem.
-          Rescue – try another strategy to see if that gets round the problem
-          Organised panic – give up, alert the user or a log
-          False Alarm – try again
-          If you are going to trying something different or try again, you need to restore the object to the state it was in before things started going wrong
Now, how does this relate to ABAP and the class based exception system? I will say how I think it works and then people can tell me where I am wrong, and the best outcome would be feedback giving specific examples of where the class based exception system is far better than the old way of dealing with exceptions.
There are three sorts of exceptions
If I have I got this right….
A STATIC exception has to be declared in the interface of the routine and then RAISED for the exception to be dealt with elsewhere, or you can handle it locally and not put the exception in the signature. If you don’t do either, you get a syntax error.
A DYNAMIC exception is exactly the same except you don’t get a syntax error, but the program dumps at runtime.
If someone could tell me a deeper difference between those two types that would be wonderful. At first glance I can see why a dynamic exception would be worse than a static one, but nothing to say why it would be better or more appropriate in some situations.
A NO_CHECK exception is supposed to be used for system errors – things that can happen at any time – you do not need to declare it in the signature, and you can just throw the exception in the air from a deeply nested routine and hope someone somewhere up the call stack catches it. So to be really safe you need a CATCH CX_ROOT or something at the highest level.
My first thought was that having to declare exceptions in the signature was a bit of an overhead and made the programs more complicated that they needed to be.
So if you had a program with a really deep nesting level, and only the very highest level could reasonably know what to do with the error, you would have to declare the exception all the way down, and potentially the deeper you went, the longer the signature of the methods would become. An intermediate method might not ever raise the exception itself, but needs to be able to send it back, in case something that it calls raises the exception.
As always, if that logic is fundamentally flawed, as it may well be, please feel free to help me understand.
Now, in the class based exceptions we have the TRY / CATCH / CLEANUP block, which again at first glance seems overly complicated.
If the routine knows how the CATCH block will try repair the error if it can and that is what the RETRY is for ….
DATA: lf_data_is_rubbish TYPE abap_bool VALUE abap_true.

 
TRY.
     
IF lf_data_is_rubbish = abap_true.
       
RAISE EXCEPTION TYPE cx_ai_application_fault.
     
ENDIF.
   
CATCH cx_ai_application_fault.
      lf_data_is_rubbish
= abap_false.
      RETRY
.
 
ENDTRY.
If not i.e. the routine doesn’t feel up to handling the error, then gather details of what caused the error the same way a short dump does, and then propagate the error to thecaller. The CATCH needs the current damaged state of the data so it can report on it. The CLEANUP runs between the exception being raised and leaving the routine to restore the object to the state it was in before the routine began. Then the caller can fix up the calling data or something and give the routine another whirl.
Or if the routine is really complicated and reversing everything to the state at the start is a bit extreme, the exception is raised as RESUMABLE so the calling program can fix up the data and then come back to the point things left off.
*&---------------------------------------------------------------------*
*&      Form  RESUMABLE
*&---------------------------------------------------------------------*
* Routine that knows what to do with data
*----------------------------------------------------------------------*
FORM resumable .

  gf_data_is_rubbish
= abap_true.

 
TRY .
     
PERFORM do_not_know.

   
CATCH BEFORE UNWIND cx_ai_application_fault.
     
"Repair the data using special knowlegde only this level knows
     
IF gf_data_is_rubbish = abap_true.
        gf_data_is_rubbish
= abap_false.
     
ENDIF.
      RESUME
.
 
ENDTRY.
ENDFORM.                    " RESUMABLE
*&---------------------------------------------------------------------*
*&      Form  DO_NOT_KNOW
*&---------------------------------------------------------------------*
* This routine does not know how to repair data
*----------------------------------------------------------------------*
FORM do_not_know RAISING RESUMABLE(cx_ai_application_fault).

 
TRY.
 
IF gf_data_is_rubbish = abap_true.
   
RAISE RESUMABLE EXCEPTION TYPE cx_ai_application_fault.
 
ENDIF.

 
CATCH zcx_ai_application_fault.

 
CLEANUP.
   
"This never gets called due to BEFORE UNWIND above
   
MESSAGE 'Cleanup' TYPE 'I'.
 
ENDTRY.

* Now do something....

ENDFORM.                    " DO_NOT_KNOW
Break Off
I said this last time, and I am going to say it again word for word, once I have done my speech, and the presentation will be in the public domain anyway – it will be on the SAP Australian user group web site, alongside an audio recording – I will go through the contents in my next blog in as much detail as I can.
Then it will most likely be time to find another subject to waffle on about….
Cheersy Cheers
Paul
P.S. as at 09/07/2013 I still cannot see the purpose of CX_DYNAMIC_CHECK ... STATIC makes you put it in the signature, NO_CHECK lets you thow th exception in the air, DYNAMIC is the same as STATIC withoutbthe synatx checj, so what is the benefit? If you can answer this question I wll be realy grateful.
Subsequent Bogs:-
3 Comments