Skip to Content
Technical Articles
Author's profile photo Jörg Krause

The “use simple types” approach (discarded!)

After a while of experience following this approach, considering also your comments here I discarded this approach for me. I leave the original text as it is in order to archive the discussion. 

As I promised in my last post, today I come back writing about my experiences with the “use simple types” approach I mentioned there.

The approach

  • Avoid references to DDIC types (i.e. structures, data elements, table types) as long as is it is not necessary. A necessity for a DDIC type reference could be:
    • A field shows up on the screen (conversion exits and labels are needed)
    • You are calling a function module and have to match the types used here
  • Use simple, base types for attributes, locals and parameters such as:
    • string
    • integer
    • date
    • time
    • float
    • abap_bool
    • string_table (in fact, this is a DDIC type, but it is very basic and very useful when working on arrays)
  • Use range of strings in case of the need of selection ranges. Put a type definition for this in some central class of your code base. DB selections will work fine with this
  • Use clear, descriptive names for the variables in order to not create confusion about their semantics

Experiences

When I first thought of this, I was afraid, I missed something and the approach could bring more harms than blessings. So I decided to “try it out” for a while.

After having created a number of applications following the approach, I must say that it comes in very handy. I’d like to share some snippets:

    methods pbo.

    methods set_conf_number
      importing in type string.

    methods set_work_station
      importing in type string.

    methods set_test_purpose
      importing in type string.

    methods set_remarks
      importing in type string.

    methods exit_command
      importing in type string.

    methods user_command
      importing in type string.

This is part of the declaration of a front end class that communicates with a function group that carries a dynpro. Imagine how easy it was to create those declarations using copy and paste!

The dynpro logic calls those methods on each event that happens on it:

module conf_number_input input.
  g_controller->set_conf_number( conv #( zst_pp39_qcheck_strip_screen-conf_number ) ).
endmodule.

module work_station_input input.
  g_controller->set_work_station( conv #( zst_pp39_qcheck_strip_screen-work_station ) ).
endmodule.

module test_purpose_input input.
  g_controller->set_test_purpose( conv #( zst_pp39_qcheck_strip_screen-test_purpose ) ).
endmodule.

module remarks_input input.
  g_controller->set_remarks( conv #( zst_pp39_qcheck_strip_screen-remark ) ).
endmodule.

module exit_0001 input.
  g_controller->exit_command( conv #( user_command ) ).
endmodule.

module user_command_0001 input.
  g_controller->user_command( conv #( user_command ) ).
endmodule.

Since I am on the front end representation layer here, all my data is typed by referring DDIC. So I have to do a conversion when passing them to my simple-typed class.

  private section.
    constants function_preview type string value '1'.
    constants function_print type string value '2'.
    constants info_structure_name type string value `ZST_PP39_CONFIRM_INFO`.
    constants work_station_parameter type memoryid value 'ZPP24_WSTAT'.
    constants confirm_number_parameter type memoryid value 'RCK'.
    constants info_value_width type i value 12.
    constants info_description_width type i value 30.

constants (and data) declarations are dominated by simple types. However, some ABAP statements (as for instance get parameter id) require non-string parameters so I had to make some exceptions to my rule.

* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZCL_PP39_QCHECK_STRIP_BACKEND->FILL_PRINT_DATA
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RESULT                         TYPE        ZST_PP39_QCHECK_STRIP_PRINT
* +--------------------------------------------------------------------------------------</SIGNATURE>
  method fill_print_data.
    result =
      value #(
        order_id             = |{ order_operation-order_id alpha = out }|
        material_number      = zcl_ca03_conversions=>matn1_output( order_operation-material_number )
        work_center_id       = work_center_id
        work_center_text     = work_center_text
        material_description = material_description
        test_purpose_text    = test_purpose_text
        remark               = remark ).
  endmethod.

This is a mapping method for a communication structure that is used in a smart form. Since the smart form is called via function module, I had to create a DDIC structure for the data that is to be printed. However, the fields of the structures are all simple strings (see below).

Note the conversions I do for the first two fields. For printing, I need the external representation. Here, one could say that using a DDIC field in the communication structure would have done the job of conversion (and I would agree – maybe I will change this).

class ZCL_PP39_QCHECK_STRIP_TYPES definition
  public
  final abstract
  create public .

public section.
  types:
    begin of ty_order_operation,
      conf_number type string,
      order_id type string,
      activity type string,
      material_number type string,
      work_center_id type string,
    end of ty_order_operation.

This is a class where I declare complex types for use within the application. As you see, the components are all strings.

    select single
      afvc~rueck as conf_number,
      afvc~vornr as activity,
      afvc~arbid as work_center_id,
      afpo~aufnr as order_id,
      afpo~matnr as material_number
      from afvc join afko on afko~aufpl = afvc~aufpl
                join afpo on afpo~aufnr = afko~aufnr
      where afvc~rueck = @in
      into corresponding fields of @result.

Here we have a select that fills the structure declared above. Obviously the import parameter in is a string. Using into corresponding fields does the job of converting everything to strings.

    data confirm_info type zst_pp39_confirm_info.

This is a structure I use for screen output. Of course, every field in this structure has its DDIC type.

Conclusion

Coding in this way seems more lightweight to me. I like the easy way I can create new parts in my coding doubling a row or region and then changing the essential, while the type references are often identical (referring to a string).

To me, the code remains readable and clean. To understand the purpose of coding logic, normally it is sufficient to understand if I am dealing with a text, a flag or a number. The rest of the semantic comes with clear names.

 

Assigned Tags

      8 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Sandra Rossi
      Sandra Rossi

      You might also consider the memory requirement of STRING in your analysis, compared to type C:

      • ABAP Documentation – Character String and Byte String Processing for Release 7.0, EhP2 – Modification 6 – Management of Short Strings
        • The internal management of short stings has been optimized to reduce the memory overhead that accumulates when short strings are managed for the relevant string header. For string lengths of less than 30 characters or 60 bytes, the string header now only requires between 10 and 40 bytes. For longer strings, this remains at approximately 50 bytes. Before Release 7.0, EhP2, the overhead of the string header was not related to the length of the string and was approximately 60 bytes for each string.
        • Strings are recommended instead of data objects for all character string and byte string operations where a fixed length is not important.
      • ABAP Documentation – Memory Requirement for Deep Data Objects
        • For performance reasons, the memory usage of a string header depends on the length of the string. Strings with a length of less than around 30 characters/60 bytes are called short strings. The memory overhead of the string header of short strings is between approximately 10 and 40 bytes, depending on the length of the string. For all other strings, the overhead is approximately 50 bytes, regardless of the string length.
      Author's profile photo Jörg Krause
      Jörg Krause
      Blog Post Author

      I am much calmer now - performance issues were one of my fears. Thank you

      Author's profile photo Peter Inotai
      Peter Inotai

      Hi Jörg,

      Thanks for sharing your experience.

      Could you add some more info what is the advantage of using simple types instead of the standard SAP ERP types? Is it needed for the ABAP Cloud compatibility?

      Thanks,

      Peter

      Author's profile photo Jörg Krause
      Jörg Krause
      Blog Post Author

      No, this is not needed for ABAP Cloud compatibility - it's only an idea of mine, how to simplify coding.

      The initial impulse for this was a problem I had when I wanted to copy a programming utility from ERP to APO. Since I used SAP standard DDIC types in my classes and some of them did not exist in APO, the code did not compile. My starting point was: "try to depend from as few repository objects as possible!". So i wondered if I could use "data material_number type string" instead of "data material type matnr". As I described above, the application of this idea lead to a more lightweight way of coding. No more searches for the right data type - just use strings for text, i or f for numbers, d or t for date/type and so on.

      Author's profile photo Peter Inotai
      Peter Inotai

      Thanks for the info.

      Now it makes sense. I also had some similar "fun" when I moved some objects developed originally on ERP system to a Netweaver ABAP Only system. That time didn't think of this approach.

      Author's profile photo Mike Pokraka
      Mike Pokraka

      Please don't be offended when I say I am baffled by this. The data dictionary and strong typing all the way down to the db level is one of the standout features that sets ABAP apart from other languages. JavaScript's strength is in in dynamic typing, which is why we we use that for Fiori Apps and ABAP for the business end. Strong typing & DDIC integration is important enough that it warranted SAP creating two flavours of CDS Views for ABAP & HANA, so it is definitively still relevant today.

      Static and dynamic typing both have their dis/advantages, but in ABAP I personally favour static/strong typing and go dynamic/weak when there is a specific reason to.

      It's not just type safety and offloading some of the checks you would need to code (and test!) to the compiler, but also comfort. Think of some of the simple things: if I press F2 on a variable I prefer the editor to tell me it's a discount percentage with two decimals rather than just popping up with "f".

      I also can't always tell from the variable name whether someone means the internal or external WBS Element representation, the same goes for currency values.

      Also, as your first example you mention coding by copy/paste and making coding easier by not having to worry about types. ABAP already provides an elegant compromise by the use of inline declarations, and - in Eclipse at least - it's easy to use quick fixes to create method with the appropriate parameter definitions. Try it:

          data(foo) = get_data( ).
          do_stuff_with( foo ).

      Now press Ctrl-F1 on do_stuff_with and it will create the method with the correct importing parameter - without you even having to know or care what type it is.

      I can't help feeling like you've just traded simplicity of declaration by clutter with CONV #( ) operators, which can also become very tedious. I spent a fair amount of time with Gateway and OData services, at the conversion layer between generic and static typing and if anything I've come to value static typing in ABAP more.

      But that's all just my opinion, everyone is entitled to theirs 🙂

      Author's profile photo Jörg Krause
      Jörg Krause
      Blog Post Author

      I must say, you're totally right.

      Meanwhile I found out myself that this approach is no good for robust programming and readability. I edited the title and the text to point out this fact.

      Author's profile photo Mike Pokraka
      Mike Pokraka

      I think your blog is still useful, it does make some valid points, and provides a valuable perspective. But - in my opinion - it is just not something that should be applied as a blanket approach.

      Choosing the specificity of typing is a design choice that depends on each use case, and I try to keep things as specific as possible but am also happy to open up when the need arises. I'll write a method using a specific type but when another caller uses a different typed parameter then I will consider whether this is an isolated case (use CONV), or else change the parameter to something more generic like CSEQUENCE.

      I do think one issue is that SAP created way too many DDIC domains, probably because they lacked the necessary governance back in the day when awkward aberrations like WERKS/WERKS_D came about and a gazillion domains all referring to the same thing. I mean, how complex can a boolean be that you need hundreds of domains to define X and space?