CRM and CX Blogs by Members
Find insights on SAP customer relationship management and customer experience products in blog posts from community members. Post your own perspective today!
cancel
Showing results for 
Search instead for 
Did you mean: 
ceedee666
Active Contributor

This is a blog post I wanted to write for quite some time and my first try on writing a rant. And what could be a better set up for a rant than a broken heel at the beginning of summer?

Before starting to work in the area of SAP CRM and SAP IS-U most of the development I did was on the Java platform. When starting to develop on the SAP Netweaver platform two things really struck me. The first one was the lack of n modern IDE, the second one the lack of consistent, well documented, object oriented APIs. The first problem has recently been solved for by ABAP in Eclipse. The second one will be the topic of this blog post. The missing of consistent, well documented, object oriented APIs is in my opinion the result of a missing focus on API design by SAP. While some areas of the Netweaver platform offer rather nice APIs, most parts and almost all applications are lacking them.

Symptoms of the missing APIs

I think there are quite a number of issues resulting from missing API design. These range from increased development effort to problems during EhP upgrades. From my experience most of these issues are symptoms caused by the following underlying problems:

  1. Working on the wrong abstraction level
  2. Duplication of functionality by creating custom APIs

In the following section I’ll describe each of these problems and the symptoms causedby them in some more detail.

Working on the wrong abstraction level

If you follow some of the different space on SDN for some time, you will most likely recognize that some similar questions are asked again and again. These questions usually contain some patterns like, “which table stores information X”, “how is table Y linked to table Z” or “how to update table W”. These kinds of questions in my opinion usually show that someone is working on the wrong abstraction level. The underlying requirements for these questions are the need to read or update some business object stored in one of the tables. For example, instead of asking how to update table BUT050 the real requirement is how to add a business partner relation to a business partner. However, as the available APIs do not abstract from the underlying tables, developers tend to think and work on the table level rather than on the more suitable business object level.

The result of working on the wrong abstraction level is ultimately bad design and bad code quality. If developers think in terms of databases tables instead of objects they will most likely write select and update statements across their code. The result of this is code that is difficult to test and hard to maintain.

Duplication of functionality by creating custom APIs

When no suitable APIs are available developers tend to redevelop similar functionality over and over again. This is not only true for custom developments but also for the SAP standard. For example, a simple search for all usages of the BAL_LOG_MSG_ADD function module in one of our CRM systems revealed about 50 classes using this function module. The following list contains some of the classes I found:

  • CL_CRM_LOG
  • CL_CRM_BSP_CU_APPLOG
  • CL_CRM_BSP_CU_APPLOG
  • CL_DMC_APPL_LOG
  • CL_LOG_PPF

All of these classes try to wrap the function module based API of the application log with an object oriented one. Each of these classes does more or less the same with some slight variations to it. In addition to the SAP standard classes wrapping the application log I also found some Z-classes as well as on “standard” class in our own namespace.

Duplication of code or functionality is always bad design. The lack of easy to use APIs even for basic tasks like logging fosters duplication. This ultimately results in increases defect rates in custom code and leads to longer development times and / or lower quality.

Features of good API design

Good API design is an extensively discussed topic. For this blog I will use a list of features for good API design initially given by Joshua Bloch in his talk “How to design a good API and why it matter” (cf. http://lcsd05.cs.tamu.edu/slides/keynote.pdf or How to Design a Good API & Why it Matters). According to Joshua Bloch a good API is

  • Easy to learn
  • Easy to use, even without documentation
  • Hard to misuse
  • Results in easy to read and maintainable code
  • Sufficiently powerful to satisfy requirements
  • Easy to extend / evolve
  • Appropriate to the audience.

In the context of development on the SAP Netweaver platform I would extend the list above by the requirement for the API to be object oriented. In my opinion most of the APIs provided by SAP fail according to the above characteristics.

An Example of current APIs: The business partner APIs

In the following sections I will analyze the APIs currently provided by SAP with respect to the characteristics mentioned above. As an example for this analysis I will use the different APIs for business partners.

There are two business partner APIs that are regularly use in the context of SAP CRM and SAP IS-U (besides the ever so common SELECT * FROM BUT000 ;). These are

  • the business partner BAPI API
  • the CRM BOL API.

I know there are quite a number of other APIs for business partner, but for the purpose of this blog I focus on these two. The use case I will use to analyze the APIs is to search for a business partner with a given name and read its default address.

The business partner BAPI API

Using the BAPI API this use case can be implemented using the following code. Note that I did not implement any error handling here to keep the example more concise. Furthermore, I did not take into account the possibility of having different kinds (e.g. person, organization or group) of business partners to simply things further.


  DATA: search_data TYPE bapibus1006_central_search,
        search_results TYPE TABLE OF bapibus1006_bp_addr,
        central_data_person TYPE bapibus1006_central_person,
        address_guid TYPE bu_address_guid,
        address_guid_32 TYPE sysuuid_c,
        address_data TYPE bapibus1006_address,
        return_vals TYPE TABLE OF bapiret2,
        address_string TYPE string.
  FIELD-SYMBOLS: <search_result> TYPE bapibus1006_bp_addr.
  search_data-mc_name1 = 'Test'.
  CALL FUNCTION 'BAPI_BUPA_SEARCH_2'
    EXPORTING
      centraldata  = search_data
    TABLES
      searchresult = search_results
      return       = return_vals.
  READ TABLE search_results ASSIGNING <search_result> INDEX 1.
  CALL FUNCTION 'BAPI_BUPA_CENTRAL_GETDETAIL'
    EXPORTING
      businesspartner   = <search_result>-partner
    IMPORTING
      centraldataperson = central_data_person.
  CALL FUNCTION 'BAPI_BUPA_ADDRESSES_GET'
    EXPORTING
      businesspartner     = <search_result>-partner
    IMPORTING
      standardaddressguid = address_guid.
  address_guid_32 = address_guid.
  CALL FUNCTION 'BAPI_BUPA_ADDRESS_GETDETAIL'
    EXPORTING
      businesspartner = <search_result>-partner
      addressguid     = address_guid_32
    IMPORTING
      addressdata     = address_data.
  WRITE / central_data_person-fullname.
  WRITE / address_data-street && ` ` && address_data-house_no && `, ` && address_data-city.

Analyzing this piece of code and the BAPI API according to the criteria mentioned above I came to the results listed in the table below. While the analysis is certainly subjective I think it points out some of the problems with the BAPI API. In my opinion the major problem is the need to know the underlying database mode in detail to being able to use the API. In summary I think the BAPI API for business partners is not a good API with regard to the criteria.

CriteriaAnalysis

Object Oriented

The API is based on function modules and not object oriented.

Easy to learnIn my opinion the API is tied very closely to the underlying data base model. Without a sound understanding of this data base model it is very difficult to guess which function modules to use to get which data. For example, it is not clear which fields to use to search for a business partner name without knowing the underlying database model.

Easy to use, even without documentation

As stated above the API is not usable without a sound understanding of the business partner data model.

Hard to misuse

It is easy to misuse the API. For example, it is quite easy to miss the need to convert between the different GUID representations used in the API resulting in a dump during runtime.

Results in easy to read and maintainable code

As the code is based on function modules it is not very concise and therefore harder to read. However, once one understands the API the core is reasonably well read and maintainable.
Sufficiently powerful to satisfy requirements

It is definitely powerful enough to fulfill the requirements for reading, storing and updating business partner data.

Easy to extend / evolve

The API can only be extended using the enhancement techniques (e.g. BAdIs or implicit enhancement points) provided by SAP.

Appropriate to the audience.

The BAPI API is not appropriate for its audience as it forces developers to switch between an object oriented and the structured programming model. Furthermore, it requires developers to understand the underlying database model in detail.


The CRM BOL API

Implementing the same use case using the CRM BOL API results in the following code. Again I omitted some error handling as well as the handling of different business partner.


DATA: bol_core TYPE REF TO cl_crm_bol_core,
        query TYPE REF TO cl_crm_bol_query_service,
        query_result TYPE REF TO if_bol_entity_col,
        bp_entity TYPE REF TO cl_crm_bol_entity,
        address_entity TYPE REF TO cl_crm_bol_entity,
        related_entities TYPE REF TO if_bol_entity_col,
        full_name TYPE string,
        street TYPE string,
        house_nr TYPE string,
        city TYPE string.
  bol_core = cl_crm_bol_core=>get_instance( ).
  bol_core->start_up( iv_appl_name = 'BP_APPL' ).
  query = cl_crm_bol_query_service=>get_instance( 'BuilHeaderSearch' ).
  query->set_property( iv_attr_name = 'MC_NAME1'
                       iv_value = 'Test' ).
  query_result = query->get_query_result( ).
  bp_entity = query_result->get_first(  ).
  related_entities = bp_entity->get_related_entities( iv_relation_name = 'BuilAddressRel').
  address_entity = related_entities->get_first(  ).
  full_name = bp_entity->get_property_as_string( iv_attr_name = 'FULLNAME' ).
  street = address_entity->get_property_as_string( iv_attr_name = 'STREET' ).
  house_nr = address_entity->get_property_as_string( iv_attr_name = 'HOUSE_NO' ).
  city = address_entity->get_property_as_string( iv_attr_name = 'CITY' ).
  WRITE / full_name.
  WRITE / street && ` ` && house_nr && `, ` && city.

In contrast to the BAPI API the code of the BOL API is more concise and therefore a little more readable. In contrast to the BAPI API the need to use several auxiliary variables (e.g. street, house_nr and city) leads to some additional code . These auxiliary variables could be omitted if I had used the GET_PROPERTIES method instead. However, in my opinion the reading the properties individually is easier to read and therefore leads to cleaner code. While the BOL API is a significant improvement over the BAPI API with respect to readability, there are still a number of problems I see with this API. Still it is necessary to know the underlying data mode quite well in order to perform a query. Furthermore, the API uses a lot of magic strings (e.g. relation names, property names) that need to be taken from the BOL model (using transaction GENIL_MODEL_BROWSER). This complicates developing using the BOL API as, for example, code completion is not available to read relations and attributes. With respect to the API criteria above the BOL API still fails in some important areas

Criteria

Analysis

Object Oriented

The API is object oriented. However, the business objects are not first class citizens of the API.

Easy to learn

The core BOL API is reasonable easy to learn. However, the usage of the API requires a constant look up of the BOL model. Furthermore, there is no consistent implementation of the BOL model across different applications (e.g. business partner vs. IS-U integration). Sometimes certain parts of the API (e.g. certain queries) simply do not work as expected.

Easy to use, even without documentation

As stated above the core BOL API is reasonable easy to learn.

Hard to misuse

It is still easy to misuse the API resulting especially in the more advanced areas like changing entities and transaction handling.

Results in easy to read and maintainable codeThe code using the BOL API tends to be more concise then the code of the BAPI API. However, the extensive use of magic strings still results in quite unreadable code especially in more complex scenarios.

Sufficiently powerful to satisfy requirements

The BOL API is definitely powerful enough to fulfill the requirements for reading, storing and updating business partner data.

Easy to extend / evolve

The core part of the API can only be extended using the enhancement techniques (e.g. BAdIs or implicit enhancement points) provided by SAP. In contrast to that, the application model (e.g. the business partner model) can be extended using a combination of customizing and custom code.

Appropriate to the audience.

The BOL API was designed to build the CRM Web UI and enable a separation of the application data model and the underlying database model. However, I think the BOL API still is not a really usable API for business partners.


What the business partner API should look like

If I lookat the task I used to analyze the business partner APIs, namely to search for a business partner with a given name and read its default address, and think of a nice API for this I end up with something like the code below:


DATA: query TYPE REF TO cl_bp_query_serice,
      query_result_col TYPE REF TO cl_collection,
      bp TYPE REF TO cl_bp,
      bp_address TYPE cl_bp_adress,
      street TYPE string,
      house_nr TYPE string,
      city TYPE string.
query_result_col = query->query_by_name( 'Test' ).
bp = query_result_col->get_next( ).
bp_address = bp->get_standard_address( ).
street = bp_address->get_street( ).
house_nr = bp_address->get_house_nr( ).
city = bp_address->get_city( ).
WRITE / bp->get_full_name( ).
WRITE / street && ` ` && house_nr && `, ` && city.

When I look at the code of this imaginary business partner API it has multiple advantages over the existing ones:

  • It is really object oriented
  • The code is concise and readable, the intention of the code becomes immediately clear.
  • It would be very easy to learn and use without any documentation as the objects and its methods speak for themselves.
  • It’s the kind of API I as a developer are looking for.

I know that my nice imaginary API cuts some corners and omits some of the complexity that underlies the business partner data model. However, I’m sure that with a focus on API design this is what SAP APIs could look like.

Summary

So what the result of all this?

First, all SAP applications I’ve been working with suffer from the same problems, there are no suitable APIs. If you need further examples have a look at the CRM one order API or even worse some of the SPA IS-U APIs.
Second, I think SAP should focus on API design and developer productivity as an important part of the product development process. SAP products (at least the on premise solutions) are basically never used out of the box. In all SAP installations custom code is necessary to adapt the standard software to the needs of the customers. By providing usable APIs SAP could significantly reduce the necessary development efforts and implementation time, increase the quality of custom code and, ultimately, reduce the TCO of the overall solution.

So, SAP when are us starting to build some nice APIs for us?

Christian

31 Comments