Im letzten Post haben wir definiert, welche Messwerte wir bezüglich der technischen Schulden erreichen wollen. Dieser Post beschäftigt sich mit den Maßnahmen für deren Umsetzung. Die grundlegenden Aussagen meiner Posts gelten allgemein für die Softwareentwicklung. Die Beispiele beziehen sich hier auf ein Entwicklung auf Basis von JAVA.
Reduzierung der Komplexität
Es sollen wenige Zyklen und Abhängigkeiten auf allen Ebenen (Artefakte, Packages) der Software entstehen und eine lose Kopplung mit geringer Kohäsion (Zusammenhalt in Modulen) erreicht werden, da
- sie die Erweiterbarkeit erleihctern
- sie weniger fehleranfällig sind
- sie die Testbarkeit erhöhen (geringerer Aufwand bei Testerstellung, bei wenigen Abhängigkeiten)
- sie zukünftig leichter aufzuteilen sind (Partitionierung) und damit Refactorings erleichtern
Es sollen kurze Klassen, Packages, Artefakte entstehen, da diese einfacher zu verstehen sind. Außerdem sollten nicht mehr genutzter Code-Teile gelöscht werden, da sie u.a. Mehraufwände bei Refactorings verursachen. Es sollte immer klar sein, welche Teile der Software genutzt werden und auch wofür sie genutzt werden. Wie die meisten hier angesprochenen Punkte können auch nicht genutzte Softwareteile großteils automatisch erkannt und iterativ beseitigt werden.
Einheitliche Lösungswege
Es sollten Entwurfsmuster verwendet werden. Hierdurch wird erreicht, dass einheitliche Lösungswege für ähnliche Probleme verwendet werden und wir uns besser zurecht finden.
Ordnung schaffen
Es muss eine fachliche und technische Schichtung sichergestellt und hierfür fachliche Hierarchien auf allen Ebenen (Artefakte, Packages, ..) eingeführt werden. Diese erleichtern die Orientierung. Wichtig ist, dass bei Paketen die Fachlichkeit die technischen Aspekte dominiert. Es sollte also
...basedata.entity ...basedata.facade ...accounting.entity ...accounting.facade
und nicht
...entity.basedata ...entity.accounting ...facade.basedata ...facade.accounting
verwendet werden. Im ersten Fall wären alle Entitäten und Facades der Bereich in einer fachlichen Struktur zusammengefasst. Dies erleichter das Arbeiten, da bei Änderungen häufig alle fachlichen Klassen genutzt werden. Im zweiten Fall wären alle Entitäten und alle Facades der Anwendung im Paketen zusammengefasst. Dies hat zur Folge, dass bei der Bearbeitung eines Bereichs viel im Paketbaum „gesprungen“ werden muss.
Tests
Eine hohe Testabdeckung stellt sicher, dass Software das Gewollte erledigt.
Fehlerreduzierung
Eine Vielzahl von Fehlern lassen sich automatisch erkennen. Viele NPE oder falsche instanceof Vergleiche werden erkannt und sollten in der Entwicklung nicht mehr auftreten. Ebenso sollten Optimierungen wie die Verwendung von StringBuilder / StringBuffer und ArrayList statt Vector immer automatisch geprüft werden. Weiterhin tragen regelmäßige Code-Reviews und last but not least auch Datenbankintegritäts-Bedingungen zur Fehlerreduzierung bei. Den letzten Punkt habe ich explizit aufgenommen, da nach meinen Eindruck dies eigentlich selbstverständliche Thema immer weniger Beachtung findet. Dadurch wird die Datenkonsistenz und damit auch die Funktion der Software gefährdet. Wir treffen erstaunlich oft auf Datenbanken ohne jegliche Konsistenzbedingungen.
Dokumentation
Insbesondere im Quellcode ist Dokumentation sehr wichtig, da wir im Code arbeiten und diesen ohne langes Suchen schnell verstehen möchten.
Strukturelle Einheitlichkeit und Konsistenz des Codes
Für eine einfache Orientierung und schnelles Verstehen des Gesehenen sind eine durchgängig einheitliche Formatierung und möglichst einheitliche Bezeichnungen im Quellcode sehr wichtig.
Werkzeuge
In den nächsten Posts stelle ich verschiedene Werkzeuge vor, die jeweils Teile der geforderten Maßnahmen sicherstellen.