Ordnung im Quelltext

Alles in Ordnung?

Avatar von Christopher Stock

Eine gute Ordnung und Struktur in die Organisation des Quellcodes einzubringen ist grundlegend. Sie wirkt sich nicht nur positiv auf die Robustheit, Testbarkeit und Interoperabilität unserer Anwendung aus, sondern sorgt auch dafür, dass unser Programm von anderen Entwicklern leicht verstanden, übernommen und erweitert werden kann.

Unordnung ist in der Softwareentwicklung gleichzusetzen mit technischen Schulden. Unübersichtlichkeit, Wiederholungen und unerwünschte Abhängigkeiten in Quellcodes führen zu erhöhten Lieferzeiten und machen die Weiterentwicklung und Wartung eines Programms um ein Vielfaches teurer.

Ich erläutere in diesem Artikel, wie Unordnung in Softwareprojekten entstehen kann und gebe Tipps aus meiner persönlichen Erfahrung, wie man dieser mit der Etablierung einer dauerhaften Ordnungskultur entgegenwirken kann.

Wie entsteht Unordnung?

Je nachdem in welcher Konstellation und unter welchen Rahmenbedingungen die Entwicklung stattfindet, wird jeder Programmierer möglicherweise andere Gründe für Unordnung in Softwareprojekten aufzählen. Aus meiner Erfahrung gibt es hauptsächlich zwei Ursachen die dabei eine Rolle spielen und die sich gegenseitig verstärken:

Grund #1: Informationen werden redundant hinterlegt

In Anwendungen verbautes Wissen, wie beispielsweise Fachwissen, Geschäftslogik oder simple Pfadangaben, kann in Quellcode sehr leicht dupliziert werden. Hinzu kommt, dass dieses hinterlegte Wissen leider nicht sonderlich stabil ist, sondern sich relativ schnell verändern kann. Das kann durch geänderte Vorgaben des Kunden oder durch Änderungen an einer externen Bibliothek geschehen.

Wird in einem Programm dasselbe Stück Wissen an zwei oder mehr Stellen formuliert, so muss bei einer Veränderung dieses Wissens an einer Stelle daran gedacht werden, auch alle anderen Stellen zu ändern. Leider ist hier nicht die Frage, ob man daran denkt, sondern wann man es vergisst. Tatsächlich löst man hierdurch einen Albtraum bei der Wartung und bei der Weiterentwicklung eines Programms aus, der bei zunehmender Anzahl an Wiederholungen exponentiell größer wird.

Es gibt zahlreiche Entstehungsmöglichkeiten von Redundanzen im Quellcode und einige entziehen sich auch dem Einfluss eines einzelnen Entwicklers. Beispielsweise können sie unbeabsichtigt durch ein ungünstig oder unfertig durchdachtes Datenmodell der Anwendung entstehen. Wiederholungen können aber auch durch Ungeduld auftreten, weil es den Entwicklern einfacher und schneller erscheint, und werden manchmal auch bewußt in Kauf genommen, da jedes Projekt unter Zeitdruck steht.

Grund #2: Untrennbares Wissen wird auf mehrere Systemkomponenten verteilt

Oftmals findet man in Programmen Komponenten vor, die nicht in sich abgeschlossen sind und deren Änderung somit unerwünschte Seiteneffekte zur Folge haben. Je enger Softwaresysteme miteinander gekoppelt sind, desto schwieriger können sie neu kombiniert oder konfiguriert werden. Das führt zu einer geringeren Produktivität und erschwert zudem die Testbarkeit und die Wiederverwendung des Codes.

Sind Teile eines Systems hochgradig von einander abhängig, so ist ein lokal begrenzter Eingriff nur schwer möglich. Das gefährdet die Robustheit der gesamten Anwendung, denn es steigt das Risiko, dass sich das Fehlverhalten einer einzelnen Komponente auf die gesamte Applikation auswirkt.

Ordnung schaffen

Nachdem wir nun beleuchtet haben wie Unordnung entstehen kann, möchte ich einige Maßnahmen vorstellen, die aus meiner Erfahrung zu den gebräuchlichsten gehören, um zur Schaffung und Wahrung von Ordnung in Softwareprojekten beizutragen. Da es sich hierbei um fast axiomatische Ideen und praktisch universelle Methoden handelt, lassen sie sich in allen Bereichen der Softwareentwicklung anwenden.

Maßnahme #1: Ersetzen Sie Eigenimplementierungen durch Standardbibliotheken

Selbstgeschriebener Quellcode, der eigene Funktionen realisiert für die es bereits externe Standardbibliotheken gibt, sollte entfernt und dessen Aufrufe durch den Einsatz dieser Bibliothek ersetzt werden. Durch die Lösung dieses „Reinventing the Wheel“-Anti-Patterns reduziert sich die reine Masse an Code, den man selbst verwalten muss. Man kann die gesamte Testabdeckung und Weiterentwicklung dieser Funktionalitäten der externen Bibliothek selbst überlassen. Ein klassisches Beispiel hierfür sind Datumsfunktionen oder RegEx-Suchfunktionen für gebräuchliche Patterns wie E-Mail-Adressen.

Sofern die Applikation einzelne Bibliotheken auf Dateibasis einbindet, sollte man diese einzelnen Abhängigkeiten eliminieren und die Verwaltung der externen Bibliotheken durch den Einsatz eines Package-Managers im Projekt zentralisieren. Hier gibt es für jede moderne Programmiersprache einen passenden und aktuellen Package-Manager: Composer für PHP, Maven oder Gradle für Java und npm für JavaScript und TypeScript.

Maßnahme #2: Einführung sprechender Bezeichner ein und Gruppierung zusammengehöriger Werte

Die Benennung aller Bestandteile unseres Quellcodes ist elementar, um ihn für andere Entwickler verständlich und sprechend darzustellen. Daher sollten zusammengehörige Variablen und Codeteile auch durch eine einheitliche Namensstruktur repräsentiert werden.

Durch eine sprechende und vereinheitlichte Benennung von Feldern und Funktionen erschließt sich oftmals die Möglichkeit des Clusterns logisch verwandter Felder und Methoden zu einer neuen Kompilationseinheit, wie beispielsweise einer neuen Klasse oder Enumeration. Konsequenterweise wird dadurch deutlich, welche Werte und Methoden von der Logik her überhaupt nicht in den aktuellen Kontext passen und dementsprechend in eine separate Codeeinheit ausgelagert werden sollten.

Hierdurch werden plötzlich wieder ganz klare und einheitliche Strukturen und Zusammenhänge sichtbar und der Code wird wieder lesbarer und erheblich besser geordnet und organisiert. Clustern Sie zusammengehörige Programmteile und trennen Sie rigoros Codeteile, die funktional nicht zusammenpassen! Erst die konsequente Strukturierung des Quellcodes nach dessen Funktionsbausteinen ermöglicht die Organisation aller Bestandteile in gekapselte Module und unabhängige Einheiten wie beispielsweise Microservices.

Maßnahme #3: Ersetzen aller Redundanzen

Das Prinzip „Don‘t Repeat Yourself!“ gilt für alle unsere Softwareprojekte und besagt, dass jedes Stück Wissen eine einzige, eindeutige und maßgebliche Repräsentation in einem System besitzen muss.

Daher ist es obligatorisch, redundante Werte sowie Funktionen, die eine gleiche oder ähnliche Funktionsweise wie eine andere Funktion besitzen, zu entfernen und mit der bestehenden Funktion zu vereinen. Durch die Eliminierung von Doppeldeutigkeiten gewinnt man im Code deutlich mehr Übersichtlichkeit und Klarheit.

Wiederholungen aus Ungeduld und Zeitdruck durch Deadlines sind zwar einfach zu entdecken und zu behandeln, erfordern allerdings Disziplin und den Willen, vorsorglich Zeit zu investieren, um dadurch zukünftigen Ärger zu vermeiden.

Wird Wiederverwendung von Code innerhalb eines Projektteams – aber auch über die Projektgrenzen hinweg – einfach gemacht, wird diese Möglichkeit auch gerne von Entwicklern genutzt. Jedes Teammitglied sollte dazu beitragen, eine Umgebung aufzubauen, in der es einfach ist, existierendes Wissen wiederzufinden und wiederzuverwenden.

Maßnahme #4: Eliminieren aller Abhängigkeiten zwischen Softwaremodulen

Halten Sie Ihren Quellcode entkoppelt! Wenn man den Zustand eines Objektes ändern will, dann lässt man es das Objekt selbst tun. Das erreicht man einfacher, wenn man die Visibility aller Elemente des Quellcodes so gering wie möglich hält. So bleibt der Quelltext unabhängig von der Implementierung anderer und die Chancen steigen, dass alles orthogonal[1] bleibt.

Zwei oder mehr Dinge sind orthogonal, wenn Veränderungen an einem der beiden keines der anderen beeinflusst. Beispielsweise kann das Datenbanksystem ausgetauscht werden, ohne damit das Verhalten der Benutzerschnittstelle zu verändern – und man kann die Benutzerschnittstelle austauschen, ohne damit das benötigte Datenbanksystem verändern zu müssen.

Auch die Vermeidung globaler Daten ist ein Faktor, der zur Entkoppelung des Quellcodes beiträgt. Immer, wenn auf globale oder statische Daten verwiesen wird, bindet man den Quellcode an andere Komponenten, die diese globalen Daten ebenfalls verwenden. Im Allgemeinen wird Quelltext verständlicher und wartbarer sein, wenn man den nötigen Kontext explizit an Module übergibt. In objektorientierten Sprachen ist es üblich, dem Konstruktor den Kontext als Parameter zu übergeben.

Es handelt sich hierbei zwar um ein etwas unhandliches Wort, aber hat man einmal gelernt das Prinzip der Orthogonalität direkt anzuwenden, wird man unmittelbar merken, dass sich die Qualität der Software verbessert.

Ein pragmatischer Ansatz

Das genannte DRY-Prinzip und auch das Prinzip der Orthogonalität wird im Standardwerk „Der Pragamatsiche Programmierer“ von Andrew Hunt und David Thomas[2] als Grundprinzipien bezeichnet, die zum Standardrepertoire eines pragmatischen Programmierers gehören. Mit dem DRY-Prinzip versucht man, Wiederholungen in einem System zu minimieren, wohingegen man mit Orthogonalität die Abhängigkeiten zwischen den Bestandteilen eines Systems reduziert.

Wenn man das Prinzip der Orthogonalität zusammen mit dem DRY-Prinzip anwendet, wird man Systeme entwickeln, die flexibler, verständlicher und einfacher zu korrigieren, zu testen und zu pflegen sind.

Ordnung halten

Immer wenn Sie Quellcode schreiben, laufen Sie Gefahr, Wiederholungen zu formulieren oder die Orthogonalität Ihrer Anwendung zu verringern. Wenn Sie nicht ständig sowohl Ihr Tun als auch die Zusammenhänge, in denen Ihre Anwendung steht, im Auge behalten, können Sie unabsichtlich Funktionalität wiederholen, Wissen redundant formulieren oder ungünstige Abhängigkeiten in Ihrem Quellcode schaffen.

Das Einführen von Ordnung in bestehende Softwareprojekte oder in bestehenden Legacy-Code geht also Hand in Hand mit der Etablierung und Pflege einer Ordnungskultur in Ihrem Softwareteam. Setzen Sie Ordnung konsequent durch und akzeptieren Sie keine Verletzungen dieser Regeln!

Gewöhnen Sie sich an, Ihren Quelltext ständig kritisch zu betrachten. Nutzen Sie jede Gelegenheit, ihn neu zu organisieren, um seine Struktur und Orthogonalität zu verbessern. Dieses Vorgehen wird Refaktorisieren genannt und ist eines der wichtigsten Aspekte in der Softwareentwicklung.

Ordnung ist das halbe Leben ..

In meiner täglichen Arbeit als Softwareentwickler ist es für mich unerlässlich, eine konsequente Ordnung bei allen Aufgaben, die sich auf das Verwalten von Quellcodes, Dateien und allen anderen Ordnungsstrukturen beziehen, zu etablieren, zu wahren und stetig zu verbessern. Für mich persönlich ist Ordnung weitaus mehr als ein aufgeräumter Desktop oder ein gut strukturiertes Projekt. Ordnung hat für mich viel mit Harmonie und Wohlbefinden zu tun und das Streben danach kann ein ganz befriedigendes und wunderbares Gefühl sein.

Vielleicht haben Sie durch meinen Artikel auch Lust bekommen, einige Aspekte in Sachen Ordnung in Ihren Softwareprojekten zu hinterfragen oder kritisch zu beleuchten. Ich wünsche Ihnen dabei ganz viel Freude und Erfolg und stehe Ihnen für fachliche Anregungen und Rückfragen gerne unter christopher.stock@mayflower.de zur Verfügung.


[1] Der mathematische Begriff „Orthogonalität“ stammt aus der Elementargeometrie und beschreibt das Verhältnis zweier Geraden oder Ebenen, die in einem rechten Winkel aufeinandertreffen. In der Informatik hat sich der Begriff dahin entwickelt, dass damit Unabhängigkeit und Entkopplung in einem Softwareprojekt ausgedrückt wird.

[2] Andrew Hunt u. David Thomas – Der Pragmatische Programmierer, Hanser Verlag

Avatar von Christopher Stock

Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert


Für das Handling unseres Newsletters nutzen wir den Dienst HubSpot. Mehr Informationen, insbesondere auch zu Deinem Widerrufsrecht, kannst Du jederzeit unserer Datenschutzerklärung entnehmen.