Monday, August 31, 2009

Writing Thought-Provoking (Erroneous) Code

Do we learn from our mistakes? Probably not!.According to a research carried out at the Massachusetts Institute of Technology we learn more from our successes than our failures. Except that the research was carried out on Monkeys. Not sure if Monkeys analyse their mistakes as much as we, humans, do. At least programmers do analyse coding mistakes which in turn provokes thoughts and improve their understanding.

I was working on a quick prototype to manipulate the help-values for the status of CRM activities. I wrote following code and encountered an error message stating relation ' ' is still not supported.

In SAP CRM Programming, we use relations of main 'Root/Access' objects to get other objects. For example, if you have 'BTAdminH' object instance available in your program then you can use the code such as one below to get 'BTHeaderActivityExt' instance.

lr_activity_entity ?= lr_adminh_entity->get_related_entity( iv_relation_name = 'BTHeaderActivityExt' ).

I checked the BOL hierarchy and at first could not see the cause of this error. However, it did not take much time to realize the problem due to case-sensitive nature of relationship name. Relation name 'BTHeaderActivityExt' was written as ''BTHeaderActivityEXT' in code. 

In this case, the error message was not on the spot however it did give me a hint. For the Program/framework, the same relationship name but in different case does not make much sense therefore same error occurs as if the relationship does not exist at all.

Case-sensitivity is an issue because it results in loss of productivity. Though experienced developers can quickly analyse and correct these mistakes, beginners spend a lot of time solving problems related to case-sensitivity. The error messages are not very helpful either.

Another example where ABAP developers normally get problems due to case-sensitivity is ALV catalogue preparation. If you append a Field-Name in lower case, a run-time error occurs with message  GETWA_NOT_ASSIGNED [ Fieldsymbol has not yet been assigned ].As a rule of thumb, you should be cautious about case-sensitivity, whenever you are writing something within the single quotes ' ' (char/string literals) in ABAP code.

There are quite a few areas in SAP where consultants waste time due to case-sensitivity like searching for  a program, transaction or table based on its description. Another important transaction(search) where case-sensitivity should have been avoided by SAP is 'OTR Text Maintenance' [ Transaction SOTR_EDIT ].

Unlike some other languages, luckily ABAP code and identifiers such as variables, method, function or routine names etc. are case-insensitive. However, a few problems are still encountered due to case sensitivity built within a particular utility or framework.

Why can't the language/framework, itself, take care of case-sensitivity? Performance and complexity are the main reasons to keep the framework case-sensitive. So from the example, what changes may be required to make the BOL model case-insensitive without causing much performance issue?

  • Keep the relationship name as all uppercase in database and then compare after converting the string to upper case. The downside is that names can be unreadable and also lead to funny pronunciation. But that’s how we normally name table fields etc (and underscore char as separator within names – though it adds an extra character each time).
  • Use a redundant field as explained below.
In some cases, like short-texts or descriptions, it's important to keep the information 'as entered'. In that case, if you want selection or value help (F4) to work irrespective of upper or lower case text criteria then you may need another (redundant) field in database table, which is all uppercase representation of the same information. The redundancy is required to get the database selection working irrespective of the text-case entered in the selection criteria. This does add to extra memory requirement. Further, an index might be required as well for this field which may increase the burden on database.

You might be thinking that a redundant field may not be required, had there been a statement available in ABAP’s open SQL, like the one below:
WHERE UPPER(column) like ‘%upper_string%’.
Within WHERE condition, UPPER(column) is possible in the vendor specific SQLs like Oracle or MSSQL. But this statement is unavailable in ABAP’s open SQL. Actually it’s not a big loss as such because this statement will cause major performance issue since table/index scan is the only possibility rather than index-seek.

After amending the code,while still thinking about case-sensitivity, I encountered another run-time error CONVT_NO_NUMBER at the following line in the code.
DELETE gt_ddlb FROM wa_ddlb.
You will probably notice immediately that I've missed the TABLE keyword and it should have been
DELETE TABLE gt_ddlb FROM wa_ddlb.
But why didn't I get the syntax error rather than run time error. And why the run time error is complaining about wa_ddlb being a character for which number conversion is not possible. As you can figure out, this is a valid statement variant and here value specified after FROM is the index value from where all lines will be deleted.
DELETE itab FROM index_value.
The statement variant expected wa_ddlb to be of type integer (like index) hence the run time error. Also, if you miss the TABLE addition, there could be a case, where you may not get the runtime error though the functionality may not be the one you intended.

Reference Code:
 DATA:   lr_cuco                TYPE REF TO CL_ICCMP_BT_CUCOADMINH_IMPL,
        lr_entity              TYPE REF TO cl_crm_bol_entity,
        lv_process_type        TYPE crmt_process_type,
        lv_category            TYPE CRMT_ACTIVITY_CATEGORY,
        wa_ddlb                like line of gt_ddlb.

 lr_cuco ?= gr_outer->gr_cuco.
 gt_ddlb = lr_cuco->get_status_ddlb( ).

* First get the current entity using avialble instance 
*(in this case of class CL_ICCMP_BT_CUCOADMINH_IMPL)

 lr_entity ?= lr_cuco->typed_context->BTAdminH->collection_wrapper->get_current( ).

 if lr_entity is not bound.

* Now that you have base entity (BTAdminH) , 
* get the required related instance for 'BTHeaderActivityExt'.
 lr_entity ?= lr_entity->get_related_entity( iv_relation_name = 'BTHeaderActivityEXT' ).

 if lr_entity is not bound.

 lr_entity->get_property_as_value(  EXPORTING iv_attr_name = 'CATEGORY'
                                    IMPORTING ev_result    = lv_category ).

 if lv_category is initial.

 if lv_category eq 'ABC'. 
* Delete Open option from drop-down.
  READ TABLE gt_ddlb into wa_ddlb with key key = 'E0001'.
  if sy-subrc eq 0.
    delete gt_ddlb from wa_ddlb.
*   Should be     delete TABLE gt_ddlb from wa_ddlb.

On a related incident, if you are getting 'No vendor specified' message from many SAP standard transactions or custom programs, in your recently upgraded ECC6.0 system then change the message number 001 of standard message class 00 in transaction SE91. The problem is only for a few patch levels and I could not find any OSS Note regarding generic correction. However, I did find a few OSS Notes acknowledging the problem locally in a few programs. These notes only provide a local solution, by changing the message statement variant to use explicit message class [ which is incorrect/incomplete solution ].

A generic message statement variant is used in some of the transactions, which always use default message class '00' and message number '001'. However, for some specific patch levels, the message is incorrectly hard-coded as 'No vendor specified' in place of &1&2&3&4&5&6..[ check in other system ].
MESSAGE message_text TYPE message_type.
This variant of message statement calls, class CL_MESSAGE_HELPER method SET_MSG_VARS_FOR_CLIKE .
Sometimes the error messages are misleading in our context. But from the context of the program, the message stands correct and specific. As a developer,  think about all the possible causes, which may have different meaning for us but same for the program and program is complaining about one of those causes.

1 comment:

  1. Very nice, and very informative. I really enjoy your use of the new classes and methods.

    Thanks for the lesson!


Info : Comments are reviewed before they are published. SPAMs are rejected.