Skip to Content
Technical Articles

Centralised Transport Naming Standards

Background

The company I work for has a sizeable and complex SAP estate with dozens of production SAP systems and therefore an equally complex development environment.  Although development standards have been in place for a number of years, it is always a challenge to ‘encourage’ developers to adhere to them.

In the last couple of years, we have implemented a Central ATC system which has made a huge difference in being able to effectively control the quality, performance and security etc. of the code being delivered to QA systems (thanks to Olga Dolinskaja and her excellent blog post series plus Bärbel Winkler for her experience in her Central ATC implementation blog post series. Their blogs and continued help is very much apprecitated).

As well as development standards, the Transport Naming Standards are also important – especially for one particular business unit where they have developments moving to multiple QA systems and therefore knowing what goes where is paramount to ensure safe and reliable operations. Although reports had been built to provide statistics and details of transport adherence, this was all reactive and transports were routinely being released without ticket details and/or release schedule details. For audit purposes, ticket details are mandatory and for the Release Management team, the schedule details help to identify the scope for each release. The burden of correcting the transport name generally fell to a few build leads and due to the new DevOps structure and increased frequency of the releases, this was starting to consume up to 25% of their day. Not exactly an efficient use of time.

 

Benefits

The main benefit therefore was to move this burden onto individual developers and therefore the ‘pain’ was then felt at the source. This then relieved the build leads of this bottle neck and time drain, and (as it turned out) enabled them to concentrate of building more automation as a result of this implementation. The benefits can be summarised as:

  1. Significant time saved to audit transports
  2. Easier mechanism to validate all transports for the weekly release are included
  3. Futher development based on change reference number now possible to generate the scope list automatically

 

Solution

Initially I considered whether it was appropriate to built a custom ATC check to house all the development in the Central ATC, but this was not the recommended approach (see this blog post on the subject) and therefore I set about building my own solution.

The solution came in two parts:

Part One

Provide links and information to all the development standards and transport naming standards details from within SE80. See another excellent blog post by Bärbel Winkler on this subject. This was to ensure that all the standards were in easy reach of all the developers, providing them will all the information required.

 

Part Two

Transports were to be blocked at both creation and release via the CTS_REQUEST_CHECK BAdI to force the correct format – which is:

<Programme/Region>:<Project/Release/Sprint>:<Change_Ref>:<Description>:<Delta No>

  • <Programme/Region> = EPB, MOW, MDG, FSCM etc.
  • <Project/Release/Sprint> = R5, 6, QR1, OOR, WR, QR01, ELS etc.
  • <Change_Ref> = Service Now, Azure DevOps, SolMan or HPALM Ref Number
  • <Description> = Self-explanatory
  • <Delta No> = For subsequent transports for the same change ref 1, 2, 3, 4 etc.

 

Initial Scope

A single remote enabled function module within the Central ATC system was required. This was just a wrapper for a local class that was split into 3 sections. See below:

 

  DATA: lv_ok               TYPE abap_bool,
        lo_transport_checks TYPE REF TO lcl_transport_checks. " Use the local class


  CREATE OBJECT lo_transport_checks
        exporting
          request = request
          type = type
          sysid = sysid
          text = text
          owner = owner.

  IF lo_transport_checks IS BOUND.

* Read the config, mapped from the system id
    lv_ok = lo_transport_checks->get_config( ).
    IF lv_ok = abap_false.
      log = lo_transport_checks->get_log( ).
      lo_transport_checks->update_statistics( 001 ).
       RETURN.
    ENDIF.

* Check the prefix against the config
    lv_ok = lo_transport_checks->check_prefix( ).
    IF lv_ok = abap_false.
      lo_transport_checks->log_valid_prefixes( ).
      log = lo_transport_checks->get_log( ).
      lo_transport_checks->update_statistics( 002 ).
      RETURN.
    ENDIF.

* Check the transport title using regular expressions
    lv_ok = lo_transport_checks->check_title( ).
    IF lv_ok = abap_false.
      lo_transport_checks->log_follow_structure( ).
      log = lo_transport_checks->get_log( ).
      lo_transport_checks->update_statistics( 003 ).
      RETURN.
    ENDIF.
  ELSE.
    log = lo_transport_checks->log_binding_error( ).
  ENDIF.

* Also log the success
lo_transport_checks->update_statistics( 000 ).

 

The first section deals with ensuring the correct configuration was in place. Configuration tables are necessary to firstly ensure the linkage between the production systems to the respective development systems is in place.

* Read the config, mapped from the system id
    lv_ok = lo_transport_checks->get_config( ).
    IF lv_ok = abap_false.
      log = lo_transport_checks->get_log( ).
      lo_transport_checks->update_statistics( 001 ).
       RETURN.
    ENDIF.

 

Secondly, each production system can then have its own set of prefixes aligned to either a single or multiple development system scenario (in the case of dual track or more landscapes). If a valid prefix is not entered, the full set of valid prefixes is then sent back to the user, advising them of what they must do to proceed.

* Check the prefix against the config
    lv_ok = lo_transport_checks->check_prefix( ).
    IF lv_ok = abap_false.
      lo_transport_checks->log_valid_prefixes( ).
      log = lo_transport_checks->get_log( ).
      lo_transport_checks->update_statistics( 002 ).
      RETURN.
    ENDIF.

Lastly, the rest of the title is then checked using regular expressions for conformity to the correct structure.

 

* Check the transport title using regular expressions
    lv_ok = lo_transport_checks->check_title( ).
    IF lv_ok = abap_false.
      lo_transport_checks->log_follow_structure( ).
      log = lo_transport_checks->get_log( ).
      lo_transport_checks->update_statistics( 003 ).
      RETURN.
    ENDIF.
  ELSE.
    log = lo_transport_checks->log_binding_error( ).
  ENDIF.

At each section, any errors were logged and then sent back to the user in the satellite system via the local POPUP_WITH_TABLE_DISPLAY function module and a statistics table is updated for later use.

On the satellite system side, the CTS_REQUEST_CHECK BAdI has a simple stub of code as below, again with a local class to house the call to the Central ATC system.

METHOD if_ex_cts_request_check~check_before_creation.

    DATA: lv_result       TYPE sysubrc,
          lt_log          TYPE tchar255,
          lv_startpos_row TYPE sytabix,
          lv_startpos_col TYPE sytabix,
          lv_endpos_row   TYPE sytabix,
          lv_endpos_col   TYPE sytabix,
          lv_width        TYPE sytabix,
          lv_line         TYPE sytabix.

    FIELD-SYMBOLS: <lv_log> TYPE char255.

    me->remote_naming_check(
      EXPORTING
        type = type
        owner = sy-uname
      IMPORTING
          log = lt_log
        CHANGING
          text = text ).

* Initial top left corner of dialog box
    lv_startpos_row = 5.
    lv_startpos_col = 28.

    IF lt_log IS NOT INITIAL.

* Set the necessary bottom right corner
      lv_endpos_row = lines( lt_log ) + 3.

      LOOP AT lt_log ASSIGNING <lv_log>.
        lv_width = strlen( <lv_log> ).
        IF lv_width > lv_endpos_col.
          lv_endpos_col = lv_width.
        ENDIF.
      ENDLOOP.

      lv_endpos_col = lv_endpos_col + lv_startpos_col.

      CALL FUNCTION 'POPUP_WITH_TABLE_DISPLAY'
        EXPORTING
          endpos_col   = lv_endpos_col
          endpos_row   = lv_endpos_row
          startpos_col = lv_startpos_col
          startpos_row = lv_startpos_row
          titletext    = 'Error Information'
        TABLES
          valuetab     = lt_log
        EXCEPTIONS
          break_off    = 1
          OTHERS       = 2.

      RAISE cancel.

    ENDIF.
  ENDMETHOD.

 

It should also be noted that since the main logic is housed centrally and within a development system, it is always ‘live’ and therefore any changes made must be done with the greatest of care. For that reason, ABAP Unit  has been employed to ensure that a test harness is in place to provide assurance that when adding new functionality, the old functionality is not broken.

 

Secondary Scope

After being live for several weeks, further improvements were identified and have been implemented:

  1. Delta numbers were made mandatory and hence a colon number check was required
  2. Refence number type check (allowed Service Now or ADO document types)
  3. System specific additional requirements

Regardng point 3 above, catering for multiple production system requirements is not easy and although these are central standards, some systems require further checks for their own unique circumstances.  In order to cater for these while keeping the core standards clean and not introducing a series of system specific IF’s or CASE statements into the central code, the multiple use functionality of the CTS_REQUEST_CHECK BAdI was taken advantage of, as well as ensuring the correct calling sequence i.e. central standards followed by local standards via the sort order option of the BAdI.

To illustrate this, the logical architecture is shown below

With the sequence of events as follows:

So far we have, five systems (2 landscapes) attached with another 4 systems imminent. As more systems come on board, feedback is positive and improvements suggested.

 

Future Improvements

Any suggestions that are believed to be ‘good for all’ will be built into the core logic in the Central ATC system which why we were keen to centralise this in the first place. System specific developments that ‘don’t make the grade’ will be developed and supported by the respectrive system teams.

Current improvements on the backlog are:

  1. Provide a better UX than the POPUP_WITH_TABLE_DISPLAY FM. It is simple and functional but a better formatted HTML based UI would be more favourable
  2. API calls to both Service Now and Azure DevOps to validate the change reference number added to the title
  3. Configuration tables to be accessed via transactional CDS views/Fiori Elements rather than SM30 (nice to have but good excuse to develop experience in this area).

Also, I will be exploring whether it makes sense to move the functionality from the Central ATC to the SCP ABAP Environment (aka Steampunk). I’ll provide a blog on the experience when I get round to it.

 

Feedback Request

Naturally I’d be very interested to hear if anyone else has implemeted anything similar and has suggestions for improvement. Equally, I’d be interested if you just find the blog post useful 🙂

6 Comments
You must be Logged on to comment or reply to a post.
  • Wow, quite the setup you’ve implemented there, Ian!

    And, thanks for the mentions of two of my blogs.

    Here is another one in which – even though the title doesn’t mention it – I include a description of what I set up via a function module to check content of transport titles:

    Getting adventurous – planning to switch a function module from using forms to using methods

    As we didn’t yet have our central ATC-system up and running when I was creating this FM, putting it into the central system never really occured to me. On the other hand – and although we do have some rather special processes in an interesting landscape – it’s not quite as complex as yours. The biggest difference is that, anything originating in one development system will always end up in all of the test- and prod-systems on its transport path.

    Cheers

    Bärbel

    • Hi Bärbel

      Thanks for the feedback and blog post link. I’ve just had a look through it which reminded me that one of my goals (that I didn’t mention) was to code all of this within ADT and to use classes as much as possible plus any other new keywords etc. that were available in the original 7.52 environment.  I don’t tend to code much nowadays and felt the need to catchup to the corrent ways of working so I can update the development standards more effectively.  Originally the code was developed on our ‘old’ NW 7.52 system but I have now moved this to a new S/4 HANA 1909 system (not used exclusively for the Central ATC btw but still a technical system). I also used it as an opportunity to introduce some newer techniques to a colleague who helped write some sections – ABAP Unit specifically.

      BTW I’ve just started looking at porting it to Steampunk, witth the initial run of the SAP_CP_READINESS_CHECK being executed this morning. Lot’s of findings to go through but look out for a blog post on this in the near future.

      Cheers

      Ian

  • An interesting solution.

    Thanks for sharing.

    Two points:

    1. Wouldn’t tagging (e.g. CR attributes) be more readable than one long CR description?
    2. Instead of multiple implementations of BAdI CTS_REQUEST_CHECK, you may create your own BAdI definition (with multiple use) and implement it with different local validation checks.
    • Hi Shai

       

      Thanks for the points raised.  Indeed the CR attributes would be useful but of course you have to drill down into the transport to view these. Keeping them in the title means you can view the transports in a list and know where they belong.

      For point 2, perhaps I am missing the point. Can you expand on the advantage of having the bespoke BAdI definition?

       

      Cheers

      Ian

      • Regarding point 2, I just mentioned the option to create your own Z BAdI definition.

        This way, instead of duplicating/inheriting all custom logic, you can focus just on the validation check itself. e.g. in your case, you may call a new BAdI method ZTRANSPORT_CHECK->NAMING_CHECK in method remote_naming_check. For every local system (with local standards) you’ll have to implement just this part.

        • In the 2nd instance of the BAdI the only duplication of the code is the display of the log data since the validation check is local to the system anyway and does not go near the central system.

          Once I clear up a couple of ATC checks and ‘refine’ some of the code, I’ll put it on Github and add a link to it.  Bit easier to see the logic and apply it to the diagrams above then.

          Cheers

          Ian