This is a test message to test the length of the message box.
Login
ABAP Refactoring alter Reports
Erstellt von Software-Heroes

ABAP - Refactoring alter Reports (2)

132

Hier geht es um den zweiten Teil der Refactoring-Reihe. Wir zeigen dir die letzten Schritte zur Überführung des alten Codings in eine neue Form.

Werbung


Im letzten Artikel haben wir vor allem die Grundlage für den neuen Report geschaffen. Heute geht es um die Anpassungen innerhalb der Struktur, dem Aufräumen der Variablen und die Finalisierung für den Test. Wie immer ist Eclipse der größte Helfer bei der Restrukturierung des alten Codes.

 

Phase: Anpassungen

In der Anpassungsphase geht es um die ersten großen Anpassungen im Quellcode. Identifizierte Redundanzen, sowie globale Variablen werden nun verringert. Weitere Hilfsmethoden können angelegt und verwendet werden, der Code bekommt langsam seine finale Struktur.

 

 

Zusätzliche Methoden

Als Nächstes werden weitere Methoden erzeugt, um Redundanzen aus dem Coding zu bekommen und die Strukturierung des Ablaufs zu vereinfachen. Dazu legen wir eine Methode an, um den Buchungskreis zu validieren, da es sich hier um zwei gleiche Zugriffe handelt. Die Validierung des Selektionsbildes und die Selektion der Daten werden ebenfalls in eigene Methoden gepackt. Damit sollte der Code die folgende Struktur nach Abschluss aufweisen:

 

REPORT ztest_determine_bookings.

TYPES:
  BEGIN OF ts_booking,
    bukrs TYPE bkpf-bukrs,
    belnr TYPE bkpf-belnr,
    gjahr TYPE bkpf-gjahr,
    cpudt TYPE bkpf-cpudt,
    xblnr TYPE bkpf-xblnr,
    buzei TYPE bseg-buzei,
    wrbtr TYPE bseg-wrbtr,
    waers TYPE bkpf-waers,
    kostl TYPE bseg-kostl,
    prctr TYPE bseg-prctr,
    butxt TYPE t001-butxt,
  END OF ts_booking.
TYPES: tt_booking TYPE STANDARD TABLE OF ts_booking.

DATA:
  gd_date TYPE d.
FIELD-SYMBOLS:
  <gs_booking> TYPE ts_booking.


SELECTION-SCREEN BEGIN OF BLOCK b01 WITH FRAME TITLE TEXT-t01.
PARAMETERS:
  p_bukrs TYPE bkpf-bukrs,
  p_belnr TYPE bkpf-belnr,
  p_gjahr TYPE bkpf-gjahr.
SELECT-OPTIONS:
  s_date FOR gd_date.
SELECTION-SCREEN END OF BLOCK b01.


CLASS lcl_report DEFINITION FINAL.
  PUBLIC SECTION.
    METHODS:
      initialization,

      main,

      on_bukrs.

  PRIVATE SECTION.
    DATA:
      gt_data     TYPE STANDARD TABLE OF t001,
      gs_data     TYPE t001,
      gt_booking  TYPE tt_booking,
      gs_booking  TYPE ts_booking,
      go_my_table TYPE REF TO cl_salv_table.

    METHODS:
      output,

      validate_parameters
        RETURNING VALUE(rd_valid) TYPE abap_bool,

      validate_company_code
        IMPORTING
                  id_bukrs        TYPE bkpf-bukrs
        RETURNING VALUE(rd_valid) TYPE abap_bool,

      selection.
ENDCLASS.

CLASS lcl_report IMPLEMENTATION.
  METHOD initialization.
    DATA ls_date LIKE LINE OF s_date.
    ls_date-sign = 'I'.
    ls_date-option = 'BT'.
    ls_date-low = '20200101'.
    ls_date-high = sy-datum.
    APPEND ls_date TO s_date.
  ENDMETHOD.


  METHOD on_bukrs.
    IF p_bukrs IS NOT INITIAL.
      IF validate_company_code( p_bukrs ) = abap_false.
        MESSAGE 'Company Code is not valid!' TYPE 'E'.
      ENDIF.
    ENDIF.
  ENDMETHOD.


  METHOD main.
    IF validate_parameters( ) = abap_false.
      RETURN.
    ENDIF.

    selection( ).

    output( ).
  ENDMETHOD.


  METHOD validate_parameters.
    IF p_bukrs IS INITIAL OR p_belnr IS INITIAL OR p_gjahr IS INITIAL.
      MESSAGE 'Required fields not filled!' TYPE 'E'.
      rd_valid = abap_false.
    ELSE.
      IF validate_company_code( p_bukrs ) = abap_false.
        MESSAGE 'Company Code is not valid!' TYPE 'E'.
        rd_valid = abap_false.
      ELSE.
        rd_valid = abap_true.
      ENDIF.
    ENDIF.
  ENDMETHOD.


  METHOD selection.
    DATA:
      ls_bkpf TYPE bkpf,
      ls_bseg TYPE bseg.

    SELECT * FROM bkpf INTO ls_bkpf
      WHERE bukrs = p_bukrs
        AND belnr = p_belnr
        AND gjahr = p_gjahr.

      SELECT * FROM bseg INTO ls_bseg
        WHERE bukrs = p_bukrs
        AND belnr = p_belnr
        AND gjahr = p_gjahr.

        CLEAR gs_booking.
        MOVE-CORRESPONDING ls_bkpf TO gs_booking.
        gs_booking-buzei = ls_bseg-buzei.
        gs_booking-wrbtr = ls_bseg-wrbtr.
        gs_booking-kostl = ls_bseg-kostl.
        gs_booking-prctr = ls_bseg-prctr.
        APPEND gs_booking TO gt_booking.

      ENDSELECT.

    ENDSELECT.

    SELECT * FROM t001 INTO TABLE gt_data.

    LOOP AT gt_booking ASSIGNING <gs_booking>.
      READ TABLE gt_data INTO gs_data
        WITH KEY bukrs = <gs_booking>-bukrs.
      IF sy-subrc = 0.
        <gs_booking>-butxt = gs_data-butxt.
      ENDIF.
    ENDLOOP.
  ENDMETHOD.


  METHOD output.
    cl_salv_table=>factory(
      IMPORTING
        r_salv_table = go_my_table
      CHANGING
        t_table = gt_booking
    ).

    go_my_table->display( ).
  ENDMETHOD.


  METHOD validate_company_code.
    SELECT SINGLE * FROM t001 INTO gs_data WHERE bukrs = id_bukrs.
    rd_valid = xsdbool( sy-subrc = 0 ).
  ENDMETHOD.
ENDCLASS.


INITIALIZATION.
  DATA(go_report) = NEW lcl_report( ).
  go_report->initialization( ).

AT SELECTION-SCREEN ON p_bukrs.
  go_report->on_bukrs( ).

START-OF-SELECTION.
  go_report->main( ).

 

Globale Variablen

In diesem Schritt versuchen wir die globalen Variablen zu entfernen bzw. zu minimieren. Dazu schaust du dir am besten die letzten globalen Variablen an und gehst Methode für Methode durch, welche Daten nun eigentlich lokal sind. Bei diesem Schritt werden auch die Parameter für die Methoden definiert.

Am Ende kannst du über Eclipse die Funktion "Source Code -> Delete unused variables (all)" ausführen, um alle ungenutzten Variabeln zu entfernen. Schnell wirst du feststellen, dass keine Variablen mehr übrig sind und keine global benötigt wird.

 

Umbenennen

Bei diesem Schritt benennen wir die Methoden noch etwas sprechender, um zu verstehen, was der Report und die einzelnen Schritte nun tun. Du solltest hier auch alles auf die aktuellen Namenskonventionen einstellen, um deine ATC Prüfung zu bestehen. Ebenfalls sollten die ältesten Sprachkonstrukte aus dem Quellcode verschwunden sein, also mindestens das, was bereits durch die SAP als obsolet gekennzeichnet ist.

 

Am Ende der Phase sollte der Quellcode dann ungefähr so aussehen:

 

REPORT ztest_determine_bookings.

DATA:
  gd_date TYPE d.

SELECTION-SCREEN BEGIN OF BLOCK b01 WITH FRAME TITLE TEXT-t01.
PARAMETERS:
  p_bukrs TYPE bkpf-bukrs,
  p_belnr TYPE bkpf-belnr,
  p_gjahr TYPE bkpf-gjahr.
SELECT-OPTIONS:
  s_date FOR gd_date.
SELECTION-SCREEN END OF BLOCK b01.


CLASS lcl_report DEFINITION FINAL.
  PUBLIC SECTION.
    TYPES:
      BEGIN OF ts_booking,
        bukrs TYPE bkpf-bukrs,
        belnr TYPE bkpf-belnr,
        gjahr TYPE bkpf-gjahr,
        cpudt TYPE bkpf-cpudt,
        xblnr TYPE bkpf-xblnr,
        buzei TYPE bseg-buzei,
        wrbtr TYPE bseg-wrbtr,
        waers TYPE bkpf-waers,
        kostl TYPE bseg-kostl,
        prctr TYPE bseg-prctr,
        butxt TYPE t001-butxt,
      END OF ts_booking,
      tt_booking TYPE STANDARD TABLE OF ts_booking WITH DEFAULT KEY.

    METHODS:
      initialization,

      main,

      on_bukrs.

  PRIVATE SECTION.
    METHODS:
      output_booking
        IMPORTING
          it_booking TYPE tt_booking,

      validate_parameters
        RETURNING VALUE(rd_valid) TYPE abap_bool,

      validate_company_code
        IMPORTING
                  id_bukrs        TYPE bkpf-bukrs
        RETURNING VALUE(rd_valid) TYPE abap_bool,

      selection
        RETURNING VALUE(rt_booking) TYPE tt_booking.
ENDCLASS.

CLASS lcl_report IMPLEMENTATION.
  METHOD initialization.
    DATA:
      ls_date LIKE LINE OF s_date.

    ls_date-sign = 'I'.
    ls_date-option = 'BT'.
    ls_date-low = '20200101'.
    ls_date-high = sy-datum.
    APPEND ls_date TO s_date.
  ENDMETHOD.


  METHOD on_bukrs.
    IF p_bukrs IS NOT INITIAL AND validate_company_code( p_bukrs ) = abap_false.
      MESSAGE 'Company Code is not valid!' TYPE 'E'.
    ENDIF.
  ENDMETHOD.


  METHOD main.
    IF validate_parameters( ) = abap_false.
      RETURN.
    ENDIF.

    DATA(lt_booking) = selection( ).

    output_booking( lt_booking ).
  ENDMETHOD.


  METHOD validate_parameters.
    IF p_bukrs IS INITIAL OR p_belnr IS INITIAL OR p_gjahr IS INITIAL.
      MESSAGE 'Required fields not filled!' TYPE 'E'.
      rd_valid = abap_false.
    ELSE.
      IF validate_company_code( p_bukrs ) = abap_false.
        MESSAGE 'Company Code is not valid!' TYPE 'E'.
        rd_valid = abap_false.
      ELSE.
        rd_valid = abap_true.
      ENDIF.
    ENDIF.
  ENDMETHOD.


  METHOD selection.
    DATA:
      ls_booking TYPE ts_booking,
      ls_bkpf    TYPE bkpf,
      ls_bseg    TYPE bseg.

    SELECT * FROM bkpf INTO ls_bkpf
      WHERE bukrs = p_bukrs
        AND belnr = p_belnr
        AND gjahr = p_gjahr.

      SELECT * FROM bseg INTO ls_bseg
        WHERE bukrs = p_bukrs
        AND belnr = p_belnr
        AND gjahr = p_gjahr.

        CLEAR ls_booking.
        MOVE-CORRESPONDING ls_bkpf TO ls_booking.
        ls_booking-buzei = ls_bseg-buzei.
        ls_booking-wrbtr = ls_bseg-wrbtr.
        ls_booking-kostl = ls_bseg-kostl.
        ls_booking-prctr = ls_bseg-prctr.
        APPEND ls_booking TO rt_booking.

      ENDSELECT.
    ENDSELECT.

    SELECT * FROM t001 INTO TABLE @DATA(lt_company_codes).

    LOOP AT rt_booking ASSIGNING FIELD-SYMBOL(<ls_booking>).
      READ TABLE lt_company_codes INTO DATA(ls_company_code)
        WITH KEY bukrs = <ls_booking>-bukrs.
      IF sy-subrc = 0.
        <ls_booking>-butxt = ls_company_code-butxt.
      ENDIF.
    ENDLOOP.
  ENDMETHOD.


  METHOD output_booking.
    DATA(lt_booking) = it_booking.

    cl_salv_table=>factory(
      IMPORTING
        r_salv_table = DATA(lo_my_table)
      CHANGING
        t_table = lt_booking
    ).

    lo_my_table->display( ).
  ENDMETHOD.


  METHOD validate_company_code.
    SELECT SINGLE * FROM t001 INTO @DATA(ls_data) WHERE bukrs = @id_bukrs.
    rd_valid = xsdbool( sy-subrc = 0 ).
  ENDMETHOD.
ENDCLASS.


INITIALIZATION.
  DATA(go_report) = NEW lcl_report( ).
  go_report->initialization( ).

AT SELECTION-SCREEN ON p_bukrs.
  go_report->on_bukrs( ).

START-OF-SELECTION.
  go_report->main( ).

 

Phase: Abschluss

In der Abschlussphase geht es vor allem um finale Anpassungen, Performance und Code-Optimierungen, um den finalen Report noch "rund" zu machen. Hier könnte man sich z.B. auch die Selects anschauen und etwas optimieren. Weiterhin sollte der Report in einen übersetzungsfähigen und testfähigen Stand kommen.

 

 

Format

In diesem Schritt werden die Methoden und Funktionsbausteinaufrufe, sowie die Selects in einen ordentlich formatierten Stand gebracht. Dabei können sich die Feldlisten der Selects angeschaut werden, vor allem wenn mit der Wildcard * gearbeitet wird, ob wirklich alle Felder benötigt werden.

 

Texte

Nun geht es daran alle Texte in Textsymbole auszulagern, damit die Übersetzbarkeit des Reports gewährleistet ist. Weiterhin sollten Nachrichten ebenfalls in eigene Nachrichtenklassen ausgelagert werden, damit diese ebenfalls sauber übersetzt werden können.

Auch wenn dein System vielleicht aktuell nur eine Sprache unterstützt, so könnte in Zukunft vielleicht Mehrsprachigkeit ein Thema werden. In diesem Fall wären alle deine Objekte auf diesen Fall vorbereitet.

 

Test

Das Wichtigste dann zum Schluss, der eigentliche Test der Funktionalität. Verhält sich der Report noch so, wie er sollte? Hier muss der Report und seine Funktionen noch einmal vollständig geprüft und getestet werden. Es lohnt sich in den meisten Fällen auch noch einen Unit Test zu schreiben und so die Funktionen automatisch zu testen.

 

Ergebnis

Hier noch einmal das finale Ergebnis des Reports nach Übernahme und Bereinigung der Entwicklung. Dieser ist nun einfacher und günstiger zu Warten und warhsceinlich einfacher verständlich für jeden Entwickler. Bei der Optimierung haben wir noch einige Punkte aus dem Clean Code for ABAP Konzept implementiert, um so den Quellcode noch etwas aufgeräumter zu machen.

 

REPORT ztest_determine_bookings.

DATA:
  gd_date TYPE d.

SELECTION-SCREEN BEGIN OF BLOCK b01 WITH FRAME TITLE TEXT-t01.
PARAMETERS:
  p_bukrs TYPE bkpf-bukrs,
  p_belnr TYPE bkpf-belnr,
  p_gjahr TYPE bkpf-gjahr.
SELECT-OPTIONS:
  s_date FOR gd_date.
SELECTION-SCREEN END OF BLOCK b01.


CLASS lcl_report DEFINITION FINAL.
  PUBLIC SECTION.
    TYPES:
      BEGIN OF ts_booking,
        bukrs TYPE bkpf-bukrs,
        belnr TYPE bkpf-belnr,
        gjahr TYPE bkpf-gjahr,
        cpudt TYPE bkpf-cpudt,
        xblnr TYPE bkpf-xblnr,
        buzei TYPE bseg-buzei,
        wrbtr TYPE bseg-wrbtr,
        waers TYPE bkpf-waers,
        kostl TYPE bseg-kostl,
        prctr TYPE bseg-prctr,
        butxt TYPE t001-butxt,
      END OF ts_booking,
      tt_booking TYPE STANDARD TABLE OF ts_booking WITH DEFAULT KEY.

    METHODS:
      initialization,

      main,

      on_bukrs.

  PRIVATE SECTION.
    METHODS:
      output_booking
        IMPORTING
          it_booking TYPE tt_booking,

      validate_parameters
        RETURNING VALUE(rd_valid) TYPE abap_bool,

      validate_company_code
        IMPORTING
                  id_bukrs        TYPE bkpf-bukrs
        RETURNING VALUE(rd_valid) TYPE abap_bool,

      selection
        RETURNING VALUE(rt_booking) TYPE tt_booking.
ENDCLASS.

CLASS lcl_report IMPLEMENTATION.
  METHOD initialization.
    INSERT VALUE #( sign = 'I' option = 'BT' low = '20200101' high = sy-datum ) INTO TABLE s_date[].
  ENDMETHOD.


  METHOD on_bukrs.
    IF p_bukrs IS NOT INITIAL AND validate_company_code( p_bukrs ) = abap_false.
      MESSAGE TEXT-001 TYPE 'E'.
    ENDIF.
  ENDMETHOD.


  METHOD main.
    IF validate_parameters( ) = abap_false.
      RETURN.
    ENDIF.

    DATA(lt_booking) = selection( ).

    output_booking( lt_booking ).
  ENDMETHOD.


  METHOD validate_parameters.
    IF p_bukrs IS INITIAL OR p_belnr IS INITIAL OR p_gjahr IS INITIAL.
      MESSAGE TEXT-002 TYPE 'E'.
      rd_valid = abap_false.
    ELSE.
      IF validate_company_code( p_bukrs ) = abap_false.
        MESSAGE TEXT-001 TYPE 'E'.
        rd_valid = abap_false.
      ELSE.
        rd_valid = abap_true.
      ENDIF.
    ENDIF.
  ENDMETHOD.


  METHOD selection.
    SELECT bukrs, belnr, gjahr, cpudt, xblnr, waers
      FROM bkpf
      WHERE bukrs = @p_bukrs
        AND belnr = @p_belnr
        AND gjahr = @p_gjahr
      INTO TABLE @DATA(lt_bkpf).

    LOOP AT lt_bkpf INTO DATA(ls_bkpf).
      SELECT buzei, wrbtr, kostl, prctr
        FROM bseg
        WHERE bukrs = @p_bukrs
          AND belnr = @p_belnr
          AND gjahr = @p_gjahr
        INTO TABLE @DATA(lt_bseg).

      LOOP AT lt_bseg INTO DATA(ls_bseg).
        DATA(ls_booking) = CORRESPONDING ts_booking( ls_bkpf ).
        ls_booking = CORRESPONDING #(  BASE ( ls_booking ) ls_bseg ).
        INSERT ls_booking INTO TABLE rt_booking.
      ENDLOOP.
    ENDLOOP.

    LOOP AT rt_booking ASSIGNING FIELD-SYMBOL(<ls_booking>).
      SELECT SINGLE butxt
        FROM t001
        WHERE bukrs = @<ls_booking>-bukrs
        INTO @<ls_booking>-butxt.
    ENDLOOP.
  ENDMETHOD.


  METHOD output_booking.
    DATA(lt_booking) = it_booking.

    cl_salv_table=>factory(
      IMPORTING
        r_salv_table = DATA(lo_my_table)
      CHANGING
        t_table = lt_booking
    ).

    lo_my_table->display( ).
  ENDMETHOD.


  METHOD validate_company_code.
    SELECT SINGLE * FROM t001 INTO @DATA(ls_data) WHERE bukrs = @id_bukrs.
    rd_valid = xsdbool( sy-subrc = 0 ).
  ENDMETHOD.
ENDCLASS.


INITIALIZATION.
  DATA(go_report) = NEW lcl_report( ).
  go_report->initialization( ).

AT SELECTION-SCREEN ON p_bukrs.
  go_report->on_bukrs( ).

START-OF-SELECTION.
  go_report->main( ).

 

Fazit

Mit unserer kleinen Hilfe sollte das Refactoring bzw. die Migration von Reports nun kein Problem mehr für dich sein. Schritt für Schritt kommst du nun dem Ziel etwas näher und nach jeder Phase hast du ein konsistentes Ergebnis, welches du weiter verbessern kannst. Am Ende solltest du vor allem viel Wert auf Clean Code legen, damit der Report auch zukunftssicher ist.


Enthaltene Themen:
HANA MigrationAltes CodingRefactoring
Kommentare (0)



Und weiter ...

Bist du zufrieden mit dem Inhalt des Artikels? Wir posten jeden Freitag neuen Content im Bereich ABAP und unregelmäßig in allen anderen Bereichen. Schaue bei unseren Tools und Apps vorbei, diese stellen wir kostenlos zur Verfügung.


ABAP - Refactoring alter Reports (1)

Kategorie - ABAP

Du willst einen alten Report mal komplett Überarbeiten oder sollst diesen auf ein neues System bringen, da ihr gerade eine HANA Migration macht? Kein Problem, wir zeigen dir ein paar Schritte, wie dir das gelingt.

18.09.2020

ABAP Tools - Arbeiten mit Eclipse (Refactoring)

Kategorie - ABAP

Im heutigen Artikel geht es um das Arbeiten mit Eclipse und wie du effizient und schnell dein Refactoring am Quellcode durchführen kannst

24.07.2020