Skip to Content
Personal Insights

A special treat on a sunny Saturday: ABAP CodeRetreat Hohenlohe!

A couple of weeks ago, I had happened upon Damir Majer‘s and Jürgen Creyaufmüller‘s announcement for the ABAP CodeRetreat Hohenlohe. Encouraged by a colleague who had attended one of Damir’s events a couple of years ago – but not really knowing what I was getting into – I registered for the event. It was planned to take place at Würth IT GmbH Waldzimmern in Niederhall on June 29, 2019.

As the date approached, I started to look into options to get from Fellbach to Niederhall – ideally via public transport as I’m not too keen to drive unknown routes by car. Luckily enough, it wasn’t too much of a hassle to at least get quite close to the event’s location – even on a Saturday – as the nearest train station in Neuenstein is only about 12 km away. To get there from Fellbach only involved switching trains twice and a bit more than 90 minutes all told – not much longer than taking the car, but much more relaxing for me! Lukas Weidmann, one of the other participants, was kind enough to pick me up at the train station in the morning and drop me off again in the afternoon.


Route from Fellbach (near Stuttgart in southern Germany) to Neuenstein. Niederhall is a bit to the north of that on the other side of the highway.

Getting started

Shortly after 9 am the CodeRetreat kicked off with some introductory remarks from our host at Würth IT in a pleasantly cool meeting room where about 25 participants had gathered by then. Most of them were with Würth IT but some were from other companies like myself. Then, Damir set the stage of what was going to happen during the day:

  • Plan for the day (see the slides)
  • Tips for Eclipse
  • Demo for Test Driven Development (TDD)
  • Four sessions of pair programming with TDD
  • regular breaks in between

What I liked right away, were the rules for the day:

  • We are here to learn
  • no pressure
  • prevent the usual shortcuts
  • find new ways
  • go slow
  • leave the comfort zone
  • strive for perfection
  • take the time
  • today you get the time
  • nothing has to get done
  • and my favorite: ENJOY!

Pair programming – a new experience for me

Only having heard about pair programming in the openSAP course Writing testable code for ABAP, this was my first chance to actually give it a try and experience it first hand. In order to find a programming partner, Damir asked us to sort ourselves by experience with TDD with the most experienced participants positioned on one side of the room and the least experienced ones on the other side. We paired up by who we faced on the other side of the room: very experienced with least experienced making the start and then going down the lines. By coincidence, my first programming partner turned out to be Tatjana who had been sitting next to me until then.

The programming task for the day had the enticing title “Game of life”, which had some rules for cells on a board in need of being converted into code: depending on how many neighbors a living cell has it either dies or lives for the next iteration and – something I called “the zombie rule” – a dead cell could come alive with exactly 2 neighbors (if I remember that particular rule correctly!).

After briefly introducing ourselves to our programming partner, we first had to decide which aspect of the game to focus on. We settled on creating the tests and rules for when a cell lives or dies and see how far we’d get with that within the 45 minutes we had available. One aspect of pair programming – and definitely something to get used to! – is to only work with one laptop and to take turns at the keyboard, switching roles every 10 minutes or so during this first round.

The “no pressure” rule came in handy as Tatjana explained what we were actually doing (or trying to do!) while moving along and we did get about a handful of testcases for the rules defined. Along the way I picked up some of the “new” ABAP features available since NW 7.40 like the COND-statement to create code like this instead of nested IFs-ELSEIFs:

  METHOD determine_cell_state.

    rv_cell_state = COND #( WHEN iv_aliv_nbrs < 2 THEN abap_false
                            WHEN iv_aliv_nbrs = 3 AND iv_cell_current_state = abap_false THEN abap_true
                            WHEN iv_aliv_nbrs = 2 AND iv_cell_current_state = abap_false THEN abap_false
                            WHEN iv_aliv_nbrs = 2 OR iv_aliv_nbrs = 3 THEN abap_true
                            ).

  ENDMETHOD.

As “time flies if you are having fun”, the 45 minutes Damir had given us passed away quickly – but, as “nothing had to get done”, it didn’t much matter that we abandoned our code in the middle of somewhere. In a short round of feedback several participants shared how it went for them, which piece of the exercise they decided to tackle (some went for the grid, while others for the rules), what they learned and how the experience felt for them.

By then, it was time for lunch and we enjoyed tasty food organised by Jürgen (thanks for a good selection!) and used the break to get to know some of the other participants and their respective challenges and development settings.

All good things come in threes

Which is why we had three more pair programming sessions during the afternoon!

After lunch, we paired up for the 2nd round of programming, this time matched by how experienced – or not – we were with ABAP OO. The rules for the keyboard usage changed, with the plan being that we switch quickly back and forth, from typing the test to typing the code and then the next test. Damir also instructed us to completely erase the code we had written in the first session in order to really start from scratch. I’ll admit that I ignored this instruction – remember „no pressure“! – as I wanted to keep the code for later reference. I just created a new piece of code with my 2nd partner who turned out to be Jürgen and we decided to give testing and coding the grid-layout a try but didn’t really get very far as picturing what and how to do turned out to be rather tricky – at least for me. And I can only partially blame the warm summer weather for that as we weren’t really affected by it in the air conditioned meeting room!

Then came the next two rounds of pair programming where we first paired up by the colors of our t-shirts from dark to light (I’m sure this must have some hidden connection to coding experience, right?) and then with a participant we hadn‘t been programming with before. Apart from that, the task was the same with starting from scratch, and still involving “Game of life”. One of these two rounds was a “free for all” in which we could, if we so chose, start with a procedural program and key that in as quickly as possible, not doing any tests at all. But, after about 30 minutes of that, Damir threw us a curve ball by now instructing us to create tests for the code! Quite the challenge with just about 10 minutes left to do it! But – and this was the biggest suprise for me – it turned out that you can actually call form routines from within a unit test! Not really sure if you should use this, but it’s at least an option to potentially introduce at least some unit tests into old procedural code.

And with that, it’s time for my

Take-aways from the ABAP CodeRetreat in Niederhall

Here are some things I learned and/or gained more insights on:

  • some Eclipse options I hadn’t come across before
  • how pair programming works
  • scratching the surface of TDD, but not really sure if it’s “my thing” for the kind of programs I usually write
  • likewise, scratching the surface of unit testing
  • getting some more insights about a few of the “new” ABAP constructs
  • last but not least, the realisation that unit testing can call form routines if need be, something I’m going to try out sooner rather than later

All told, the CodeRetreat was worth attending – even on a sunny Saturday at the end of June. Thanks to Jürgen and Damir for organising and Würth IT for hosting it!

Here is Damir’s tweet about the event as a “parting shot”:

4 Comments
You must be Logged on to comment or reply to a post.
  • I went to one in Luzern – same format. It was also very sunny.

    For one of the rounds, I recall that my partner wrote the tests and I wrote the code to pass the tests. Only I decided to be as lazy as possible and write the minimum (well written) code that cause the tests to all go green. Obviously this did not mean the program worked in any meaningful way.

    However, it was observable that as my partner wrote more tests, I was more constrained to produce the functionality required. I could see the solution was slowly appearing. My partner, on the other side, said that because I was being so awkward, he was forced to write comprehensive tests. If we’d continued to the end we would have a had a well written program, implementing all the required functionality (and no more), coupled with a rock solid set of unit tests.

    I gave this as feedback, and we were told this is sometimes called “the evil coder” technique.

    Pair programming has its benefits – we can all learn from each other. I’m convinced about unit tests, but not so convinced about TDD (though I still do it from time to time – currently on a pet project in Java writing an assembler).

    While you can write unit tests for ABAP procedural code, I’m not sure how you cope with test isolation – E.g. not actually sending the email that’s created in the form – when you don’t have the techniques of injection and polymorphism that come with ABAP Objects.

    • Thanks for your feedback, Matt! The “evil coder technique” has a nice mischievous ring to it!

      Given that creating unit tests for anything needing an “injection” or making use of polymorphism (what’s that, again?!?), I’m not really worried about that constraint. Instead, I see creating simple unit tests for some suitable form routines as a chance to quickly try unit testing in an “environment” where not everything looks and feels alien to me. So, it fits nicely with Damir’s reminder to take “baby steps”.

      Cheers

      Bärbel

      • Definitely baby steps.

        Injection works like this:

        I create an interface with a method to send an email – recipient parameters, body of the email etc.. I implement this interface in a class. The class does all the CL_BCS stuff exactly as it would if it were in my main program.

        CLASS-DATA _sender TYPE REF TO zif_email_sender.
        METHOD class_constructor.
          _sender = NEW zcl_email_sender( ). " This class sends emails
        ENDFORM.
        
        METHOD what_i_want_test.
          ...
          " Having done a lot of work, send the email to the figured out recipient
          _sender->send_email_to( i_to_recipient = recipient ... ).
        ENDMETHOD.

        For the test, I create an local test double, which also implements the interface, but instead of sending the email, it just sets some attributes corresponding to the parameters. My test code looks something like this:

          DATA:
            sender TYPE REF TO ltd_email_sender,
            cut TYPE REF TO class_im_testing.
        
          METHOD setup.
            sender = NEW #( ). " Instance of test double
            cut = NEW #( ).
            cut->_sender ?= sender.
          ENDMETHOD.
        
          METHOD testing.
            cut->what_i_want_to_test( ).
            cl_abap_unit_assert=>assert_equals( exp = 'to recipient' act = sender->to_recipient ).
          ENDMETHOD.

        So I test the method, no actual email is sent, and I can check the recipient has been correctly determined (for example).

        But I think I’ve answered my own question. You could do this with forms. You’ll need the same interface, class and test double, but this should work.

        DATA g_sender TYPE REF TO zif_email_sender.
        
        INITIALIZATION
          PERFORM initialise CHANGING g_sender.
        
        START-OF-SELECTION.
          PERFORM what_i_want_to-test.
        
        FORM initialise CHANGING x_sender TYPE REF TO zif_email_sender.
          x_sender = NEW zcl_email_sender( ).
        ENDFORM.
        
        FORM what_i_want_to_test USING i_sender TYPE REF TO zif_email_sender.
          ...
          " Having done a lot of work, send the email to the figured out recipient
          i_sender->send_email_to( i_to_recipient = recipient ... ).
        ENDFORM.
        
        " Test class definition
        ...
          DATA:
            sender TYPE REF TO ltd_email_sender.
        
          METHOD setup.
            sender = NEW #( ). " Instance of test double
          ENDMETHOD.
        
          METHOD testing.
            PERFORM what_i_want_to_test USING sender.
            cl_abap_unit_assert=>assert_equals( exp = 'to recipient' act = sender->to_recipient ).
          ENDMETHOD.

        Note, the email sending class doesn’t have to do anything object oriented. Just instantiate it, then call its methods as though they were FORMs. The class is essentially equivalent to a subroutine pool.

        We’re using OO techniques only to test the procedural code.

  • You can always wrap a FORM into a method.

    METHOD dostuff.
      PERFORM dostuff USING p1 p2 p3 
                      CHANGING c1
    ENDMETHOD.

    (obviously wih the same declarations).

    Local classes are handy for this, because they still have access to all the global variables so the code should work the same.

    This is a baby steps refactoring approach. It’s easy and usually safe to change the caller. And if nothing calls the form, the next step can be to pull the code into the method and delete the FORM. This is where unit tests start to become useful, as you can then start to further refactor by moving global data into your classes and so on…