Clean ABAP

Sauberer Quellcode

(C) Brandeis Consulting.

Motivation

Das Buch _Clean Code_ von Robert C. Martin ist das Standardwerk auf dem Gebiet.

Die Grundidee:

  • Quellcode wird von Menschen viel öfter gelesen als geschrieben. Darum muss er so gut lesbar wie möglich geschrieben werden.
  • Von Anfang an sauberer Code, nicht erst wenn die Komplexität zu groß wird.
  • Code ist erst fertig, wenn er auch sauber ist
  • Sauberer Code braucht weniger Dokumentation und Kommentare


Buchempfehlung für jeden der Spaß am Programmieren hat

(C) Brandeis Consulting.

Umfrage 1

Wie viel Zeit verwendet Ihr täglich , um Code zu schreiben?

Nur schreiben ohne

  • Meetings
  • Dokumentation erstellen
  • Testen
  • Konzepte schreiben
  • Bestehenden Code analysieren, z.B. wegen Wartungsaufgaben (Debugging, Performance Optimierungen etc. )
(C) Brandeis Consulting.

Umfrage 2

Welchen Anteil davon braucht Ihr für neuen Code

Wirklich neue Methoden oder Klassen, die vorher nicht da waren.

(C) Brandeis Consulting.

Beispiele aus meiner Karriere (1/2)

CIM Fortschreibung

Ein Modul war kaum mehr um neue Features erweiterbar. Alle Änderungen haben extrem lange gedauert. Alles musste nach jeder Änderung durchgetestet werden. Auch bei Fehlerbehebungen.
Ursache:

  • Vertrauen in die Korrektheit: 0
  • Motivation der Mitarbeiter: 0
  • Zufriedenheit des Managements: 0

Trotzdem hatte es lange gedauert, bis das Re-Design dieses Moduls genehmigt wurde.

(C) Brandeis Consulting.

Beispiele aus meiner Karriere (2/2)

Transformationschaos

Im BW-Backend wurden Transformationsroutinen entwickelt. Ca. 50 Stück. Der Quellcode war teilweise über 2000 Zeilen lang in einer Methode. Jegliche Änderung war riskant, weil es viele Seiteneffekte gab.

Die ursprünglich 2 Entwickler waren nicht mehr in der Lage die laufende Wartung und notwendige Neuentwicklungen zu leisten und haben das Team verlassen. Daraufhin wurden 5 Entwickler engagiert, damit das Projekt weiter ging.

Eine vollständige Neuentwicklung nach Clean Code Prinzipien und mit sauberer Architektur war notwendig. Danach war die Wartung locker von 1 Entwickler durchzuführen.

(C) Brandeis Consulting.

Die Sprache ABAP

Jede Programmiersprache ist anders - auch ABAP.

Besonderheiten von ABAP

  • Viele obsolete oder veraltete Konstrukte
  • Sehr großer Sprachumfang
  • Viele Anweisungen und Schlüsselwörter
  • Begrenzungen bei der Länge von Klassen-, Methoden- und Tabellennamen
  • Alles muss 100% Abwärtskompatibel sein.
  • Anweisungen und Funktionsaufrufe sind teilweise sehr groß und gehen über viele Zeilen.

Darum müssen die Clean Code Prinzipien aus dem gleichnamigen Buch an die Sprache angepasst werden.

(C) Brandeis Consulting.

Clean Code in ABAP

Grundsätzlich alles in Klassen implementieren
Programme und Funktionsbausteine sind notwendiges Übel für manche Anwendungsfälle. Die eigentliche Logik gehört in Klassen.
Moderne Sprachkonstrukte verwenden
Mit Ausdrücken lässt sich vieles Kompakter und eleganter formulieren. Viele Hilfsvariablen können entfallen.
(C) Brandeis Consulting.

Granularität

Damit man den Quellcode gut erfassen kann, muss man auf allen Ebenen sauber und sorgfältig arbeiten.

Ebenen

  • Formatierung in Anweisungen
    • Ausrichtung von Parametern bei geschachtelten Funktionsaufrufen
    • Ausrichtung von Feldern in der SELECT Anweisung
    • Einzelne Leerzeilen zwischen den Klauseln.
  • Auf Ebene der Methoden
    • Saubere Formatierung
    • Logischer Aufbau
    • Klare Namen für Variablen
  • Auf Ebene der Klasse
    • Kleine Methoden - Jede Methode macht ein Ding
    • Klare Namen für Methoden und Variablen
    • Gute Klassennamen
    • Jede Klasse macht ein Ding
  • Zusammenspiel der Klassen
    • Objektorientiertes Design
    • Gute Testbarkeit
    • Klare Verantwortlichkeiten
(C) Brandeis Consulting.

Grundsätze

Entkopplung

Abhängigkeiten sollen gering gehalten werden. Wenn ich eine Klasse ändere, sollte das nur innerhalb der Klasse Auswirkungen haben.

Klare Namen

Jede Klasse, Methode, Variable, Tabelle usw. hat Namen, die uns sagen, was wir dahinter erwarten können.

Kleine Einheiten

Eine Methode ist nur so lang, dass man die Übersicht behält. Klassen haben nur die Methoden, die für einen Aspekt relevant sind.

(C) Brandeis Consulting.

DRY - Don't Repeat Yourself

Wiederhole dich nicht. Wenn der exakt gleiche Code mehrfach vorkommt, machen wir etwas falsch!

Sobald man etwas noch einmal braucht, sollte man sich überlegen, wie man eine wieder verwendbare Logik implementieren kann.

(C) Brandeis Consulting.

YAGNI - You Ain’t Gonna Need It

Das YAGNI-Prinzip (You Ain ´ t Gonna Need It) ist eines der einfachsten in der Softwareentwicklung – und doch wohl das nach dem DRY-Prinzip am häufigsten verletzte Prinzip
( Clean Code Developer, YAGNI )

Implementiere immer nur das, was heute konkret gebraucht wird. Mögliche, zukünftige Anforderungen werden noch nicht implementiert. Generische Methoden für alle möglichen künftigen Erweiterungen sind zu vermeiden.

Unkonkrete Anforderungen sind kein Grund für Flexibilität, die eigentlich nicht gebraucht wird.

Das führt heute zu schlankerem, einfacherem Code. Es gibt weniger Abhängigkeiten und reduzierte Komplexität.

Nur generisch, wenn das auch gefordert ist

Falls die Flexibilität ein Feature ist, dann muss diese aber auch vollständig spezifiziert sein. Und natürlich auch so dokumentiert und getestet werden.

(C) Brandeis Consulting.

KISS - Keep it simple, stupid

Alles sollte so einfach wie möglich gemacht werden, aber nicht einfacher.
(Albert Einstein)

Bei mehreren Optionen entscheiden wir uns immer für die einfachere, klarere und verständlichere.

(C) Brandeis Consulting.

Namen

Viele Dinge im Quellcode haben Namen:

  • Methoden
  • Klassen
  • Tabellen
  • Variablen
  • Felder
    ...

Die Qualität der Namen ist wichtig für eine gute Lesbarkeit.

(C) Brandeis Consulting.

Ungarische Notation

Die Präfixe für Datentypen und Geltungsbereich sind umstritten. Weil diese meines Wissens bei der Bahn aber üblich sind, werde ich diese verwenden:

Geltungsbereich bzw. Art

  • LT_ Lokale interne Tabelle
  • GT_ Statische interne Tabelle
  • MT_ Instanz interne Tabelle
  • IT_ Importing Tabelle
  • ET_ Exporting Tabelle
  • CT_ Changing Parameter Tabelle

Datentyp

  • LT_ Lokale interne Tabelle
  • LS_ Lokale Struktur
  • LV_ Lokales Feld bzw. skalare Variable
  • LR_ Lokale Referenz

Bei kleinen Codeeinheiten ist die ungarische Notation nicht notwendig, weil sie dort keinen Mehrwert bietet. Sie steht aber einem einfachen Refactoring entgegen.

(C) Brandeis Consulting.

Namen

Namen für Klassen, Methoden, Tabellen, Felder, Variablen etc. sind extrem wichtig. Gute Namen helfen uns, den Code schnell und richtig zu verstehen.

Gute Namen ersetzen auch manche Kommentare.

Schlechte Namen können das Lesen erschweren oder sogar irreführend sein.

Namenskonventionen helfen

Wenn Ihr Namenskonventionen habt, ist es wichtig das sich alle daran halten. Selbst wenn diese nicht 100% optimal sind.

(C) Brandeis Consulting.

Aussagekräftige Namen

Variablen sollten das ausdrücken, was man erwarten kann.

  • LT_USERS - Lokale Interne Tabelle mit Benutzerdaten
  • LT_INACTIVE_USERS - Lokale Interne Tabelle mit inaktiven Benutzern
  • ZCL_USER_MANAGEMENT - Klasse zur Verwaltung von Benutzern

Das Plural-S in den Beispielen weist übrigens auf eine Tabelle hin.

Schlecht sind Namen, die nichts sagen oder verwirren:

  • TMP - Temporär - das ist klar. Aber was steht da drin
  • VAR_1 - Durchnummerieren ist immer schlecht, das sagt nichts über den Inhalt
  • T004T - Der Bezug auf technischen Namen von anderen Objekten ist ungünstig
  • I - Wird gerne als Laufvariable verwendet. Lieber LV_INDEX verwenden...
(C) Brandeis Consulting.

Domänenbegriffe

Ein Name für ein Konzept

Sind Article, Material und Product das gleiche Ding?

Ein Glossar hilft, einheitliche Begriffe zu verwenden. Das gilt auch für Abkürzungen.

(C) Brandeis Consulting.

Abkürzungen

  • Nur wenn notwendig verwenden
  • Durchgängig verwenden, siehe Domänenbegriffe
  • Fokus auf den Unterschied
(C) Brandeis Consulting.

Klassennamen

In Klassennamen verwenden wir Nomen. Eine saubere Trennung der unterschiedlichen Aspekte zwingt uns häuft dazu, einen Namen weiter zu spezifizieren.
Beispiel: ZCL_USER reicht vielleicht nicht. Dann müssen wir spezialisieren:

  • ZCL_USER_MANAGEMENT
  • ZCL_USER_UI
  • ZCL_USER
  • ZCL_USER_SERVICE
(C) Brandeis Consulting.

Methodennamen

In Methodennamen verwenden wir Verben.

  • GET_USER
  • DEACTIVATE
  • DELETE
  • CREATE_INSTANCE

Typische Muster sollten mit Präfixen standardisiert werden:

  • Zugriffsmethoden auf Variablen mit GET und SET
    • GET_USER
    • SET_USER
  • Logische (Boolsche) bzw. Prädikatsmethoden mit IS
    • IS_USER_ACTIVE
  • Prüfungen, ob eine Bedingung erfüllt ist mit CHECK. Falls nein wird hier eine Ausnahme ausgelöst.
    • CHECK_PERIOD
(C) Brandeis Consulting.

Variablendeklaration

  • Inline Deklarationen verwenden, wo möglich: DATA(<Variablenname>)
  • Keine Wiederverwendung - jede Variable hat exakt eine Bedeutung
  • Verzicht auf Kettensätze mit Doppelpunkt und Komma. Ausnahme: Strukturtypen mit BEGIN OF / END OF.
(C) Brandeis Consulting.

Konstante

  • Zentral definieren
  • Gleichartige Konstanten in einer Struktur unterbringen
    TYPES t_rgb TYPE c LENGTH 7.
    CONSTANTS: BEGIN OF cs_color,
                 red   TYPE t_rgb VALUE '#FF0000',
                 green TYPE t_rgb VALUE '#00FF00',
                 blue  TYPE t_rgb VALUE '#0000FF',
               END OF cs_color.
  • Enumerations verwenden - die kommen später noch
(C) Brandeis Consulting.

Kommentare

Präziser Code benötigt keine Kommentare
(Clean ABAP)

Dieser Satz ist grundsätzlich richtig. Trotzdem sind Kommentare häufig hilfreich.

Nützliche Kommentare

  • Beschreiben nicht das Offensichtliche
  • Erklären Dinge, die an dieser Stelle im Code nicht sichtbar sind
  • Beschreiben Konzepte

Überflüssige Kommentare

  • Beschreiben bzw. wiederholen 1:1 den Code
  • Auskommentierter Code
  • Beschreiben von Abschnitten - Das ist überflüssig, weil aus jedem Abschnitt eine Methode mit aussagekräftigem Namen gemacht werden kann
(C) Brandeis Consulting.

TODO Kommentare

Schlüsselwörter in Kommentaren, die den weiteren Entwicklungsprozess steuern sollen sind auch möglich. Durch Konventionen kann man ihnen eine einheitliche Bedeutung geben und gezielt danach suchen.
Beispiele:

  • FIXME - Markierung eines Fehlers, der behoben werden sollte. Warum macht man das nicht gleich?
  • TODO - Hier fehlt noch etwas im Code. Das muss aber noch vor der Freigabe des Codes erledigt werden.
  • XXX - Funktioniert fehlerfrei, kann aber noch verbessert werden.

Bitte diese nur verwenden, wenn

  1. das im Team einheitlich verwendet wird und
  2. die Kommentare auch abgearbeitet werden. Dazu sollte es einen Nächtlichen Testlauf geben, der die Kommentare zählt.

Ansonsten ist das pure Prokrastination von Arbeit.

(C) Brandeis Consulting.

Formatierung

Der Pretty Printer muss stets verwendet werden. Er ist aber nur auf Anweisungsebene zu gebrauchen. Darüber hinaus gilt:

  • Alle Listen sind auszurichten, z.B.
    • Feldliste beim SELECT
    • Felder bei TYPES Anweisungen
    • Deklarationen
    • Methodenparameter
  • Bei verschachtelten Funktionen mit mehr als einem Parameter kommt jeder Parameter in eine neue Zeile.
  • Überlange Zeilen (>120) sind zu vermeiden
  • Beim SELECT kommt jede Klausel (SELECT/FROM/INTO/GRPOUP BY/ORDER BY etc. ) in eine neue Zeile.
  • Zwischen Anweisungen kann maximal eine Leerzeile eingefügt werden, wenn es der besseren Lesbarkeit dient.

Nicht formatierter Quellcode ist nicht fertig.

(C) Brandeis Consulting.

Beispiele für Formatierung - vorher und nachher

SELECT CASE WHEN ls_tmax_ut > '000000000000000' and ls_tmax_ut < '99991231235959' THEN
CAST ( TO_VARCHAR( UTCTOLOCAL( TO_TIMESTAMP (
SUBSTRING( :ls_tmax_ut,1, 12  )
|| REPLACE(SUBSTRING( :ls_tmax_ut, 13, 2  ), '60', '59' )
), 'CET' ), 'YYYYMMDDHH24MISS' ) as DEC ( 15,0 ) )
ELSE CAST ( :ls_tmax_ut as DEC ( 15,0 ) ) END
INTO ls_tsmax_lt FROM DUMMY;
SELECT CASE WHEN ls_tmax_ut > '000000000000000' 
             and ls_tmax_ut < '99991231235959' 
             THEN CAST ( TO_VARCHAR( UTCTOLOCAL( TO_TIMESTAMP ( SUBSTRING( :ls_tmax_ut,
                                                                           1, 
                                                                           12  
                                                                ) || REPLACE( SUBSTRING( :ls_tmax_ut, 
                                                                                       13, 
                                                                                       2  
                                                                               ), 
                                                                            '60', 
                                                                            '59' 
                                                                     ) 
                                                  ), 
                                                  'CET' 
                                        ), 
                          'YYYYMMDDHH24MISS' ) as DEC ( 15,0 ) )                         
             ELSE CAST ( :ls_tmax_ut as DEC ( 15,0 ) ) 
          END
INTO ls_tsmax_lt FROM DUMMY;

(C) Brandeis Consulting.

Entkopplung

Abhängigkeiten sollten reduziert werden, damit Änderungen immer nur lokale Auswirkungen haben. Beispiele für Entkopplung:

  • In der Objektorientierung
    • Kapselung der Daten durch Methoden
    • Definition der Sichtbarkeit von Komponenten
    • Verwendung von Interfaces statt konkreter Klassen
  • Wrapper um andere Module
(C) Brandeis Consulting.

Wrapper um andere Module

Wenn wir in unseren Programmen an 100 Stellen die gleichen Methoden eines anderen Moduls( oder Framework, Projekt, Produkt, ...) aufrufen, dann sollten wir diese Kapseln. D.h. wir bauen eine Klassen, die das andere Modul repräsentiert.

Damit haben wir nur noch eine Klasse, die von dem anderen Modul abhängt. Änderungen im anderen Modul können an einer Stelle zentral ausgeglichen werden. Das andere Modul hat nur eine Abhängigkeit statt 100.

Whiteboard

(C) Brandeis Consulting.

Methodenlänge

The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that. The smaller and more focused a function is, the easier it is to choose a descriptive name.
(Robert C. Martin, Clean Code)

Methoden sollen ebenfalls kurz sein.
Eine Faustregel ist: Eine Methode sollte auf einen Bildschirm pass
en.

Im Clean ABAP Buch wird eine Größe von 5 Anweisungen als optimal bezeichnet. Maximal sollen es 20 Anweisungen sein.

(C) Brandeis Consulting.

Eine Methode arbeitet nur auf einer logischen Ebene

Single Level of Abstraction (SLA)

Anweisungen können auf unterschiedlichen logischen Ebenen liegen. Beispielsweise

  • Zeichenketten zusammensetzen
  • SELECT Anweisung
  • Aufruf von anderen Methoden
  • COMMIT WORK

Wir sollten innerhalb einer Methode immer nur auf einer logischen Ebene arbeiten. Das erhöht die Lesbarkeit und erleichtert es, passende Namen für die Methoden zu finden.

(C) Brandeis Consulting.

Methoden sollen eine Aufgabe haben

Functions should do one thing. They should do it well, they should do it only.
(Robert C. Martin, Clean Code)

Das bedeutet: keine X optionalen Parameter, die alle möglichen Alternativen steuern. Wenn eine Variante der Methode benötigt wird, dann legen wir eine neue Methode an.

Das führt dazu das wir

  • passendere Namen für unsere Methode finden
  • weniger Parameter brauchen
  • nur die Anwendungsfälle implementieren, die jetzt und heute wirklich gefragt sind
  • eine einfachere Implementierung haben
(C) Brandeis Consulting.

Wenige Parameter verwenden

Je weniger Parameter eine Methode hat, desto besser lässt sie sich testen. Wenige Parameter helfen auch beim Verständnis einer Methode.

Wenn Parameter zusammengehören, können diese auch in einem Objekt oder in einer Struktur gebündelt werden.

Statt optionaler Parameter sollte lieber eine neue Methode angelegt werden.

Auch für Boolsche Parameter gilt: Einfach zwei Methoden anlegen.

Wenn eine Methode mehrere EXPORTING Parameter hat, dann macht sie sicherlich mehrere Dinge. Das widerspricht der Forderung, dass eine Methode nur eine Aufgabe haben soll.

Am besten wird ein RETURNING Parameter verwendet. Dieser sollte den Namen RESULT haben.

(C) Brandeis Consulting.

Eine Klasse soll nur eine Aufgabe haben

Single Responsibility Principle / Separation of Concerns

Die Aufgaben werden dadurch entkoppelt. Somit halten wir die Klassen klein und reduzieren die Komplexität.

(C) Brandeis Consulting.

Objektorientierte Prinzipien

  • Instanzmethode über statische Methoden
  • Komposition über Vererbung
  • Liskov Substitution Principle
(C) Brandeis Consulting.

Verwendet Instanzmethoden

Instanzmethoden sind flexibler als statische Methoden. Sie können redefiniert werden und können in UnitTests durch Test-Doubles ersetzt werden.

Instanzmethoden können hinter ein Interface gelegt werden.

Statische Methoden sind grundsätzlich nicht optimal, da sie nur über den Klassennamen oder eine Referenz aufgerufen werden können.

(C) Brandeis Consulting.

Prinzip der Schnittstellentrennung

Interface Segregation Principle (ISP)

Wenn wir keine konkreten Klassen sondern Interfaces referenzieren, dann können diese flexibel ausgetauscht werden. Entweder zu Testzwecken oder weil es irgendwann eine weitere Implementierung gibt.

Interfaces sollen nur die Methoden enthalten, die Verwender wirklich benötigen. Lieber mehrere Interfaces definieren, die dann von einer Klasse implementiert werden.

(C) Brandeis Consulting.

Liskov Substitutions Prinzip

Wenn eine Klasse von einer anderen erbt, dann muss sie sich genau wie die Superklasse verhalten.

(C) Brandeis Consulting.

Performance (1/2)

Premature optimization is the root of all evil

Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.
( Donald Knuth )

Rules of Optimization:
Rule 1: Don’t do it.
Rule 2 (for experts only): Don’t do it yet.

( M.A. Jackson )

More computing sins are committed in the name of efficiency (without necessarily achieving it) than for any other single reason – including blind stupidity.
( W.A. Wulf )

(C) Brandeis Consulting.

Performance (2/2)

Gute Modularisierung erlaubt später aussagekräftige Analyse mit der SAT. Die Optimierung wird dadurch sogar erheblich erleichtert.

Falls etwas auf Kosten der Sauberkeit optimiert werden soll:

  • Vor dem Optimieren muss auch wirklich ein relevantes Problem vorliegen
  • Die Laufzeit muss gemessen und analysiert werden. Nur bei dominanten Bereichen lohnt eine Optimierung.

Trotzdem grundsätzlich

  • Passende Typen für interne Tabellen wählen
  • Saubere Schlüsseldefinitionen verwenden
(C) Brandeis Consulting.

Legacy-Code - Der alte Sch...

Der Begriff „Legacy Code“ wird in der Software-Technik verwendet und bedeutet übersetzt so viel wie „Altcode“. Dabei handelt es sich um älteren Code, der in der Regel nicht mehr aktiv weiterentwickelt wird. ( Ionos Website )

  • Wir fassen alten Code nur an, wenn dort Änderungen notwendig sind.
  • Jedes Mal wenn man dort etwas ändern muss, kann man Kleinigkeiten optimieren. Auch "Pfadfinder Regel" genannt.
  • Neuen Code grundsätzlich nach Clean Code Prinzipien aufbauen.
(C) Brandeis Consulting.

Anfangen - Jetzt!

Das Wichtigste beim Clean Code: man muss damit anfangen. Man gewöhnt sich schnell daran. Dann ist es effektiv kein zeitlicher Mehraufwand.

Jeder kann im Kleinen anfangen, auch wenn manche Prinzipien noch nicht 100% klar sind.

(C) Brandeis Consulting.

Und wie geht es weiter?

In den nächsten Tagen lernen wir mit Modernem ABAP viele neue Sprachbestandteile, die sauberen Code leichter machen.

Ihr habt alle das Buch Clean ABAP. Einfach mal reinschauen... Und darüber hinaus kann ich das Buch Clean Code empfehlen. Auch wenn vielleicht nicht alles zu 100% auf ABAP passt, so ist es noch immer das Standardwerk zu dem Thema.

Buch Clean Code als PDF
Clean Code Developer Initiative
Index


Clean Code von Robert C. Martin
ISBN-13: 9780136083221

(C) Brandeis Consulting.