© saicle/Shutterstock.com
Mit 3 Prinzipien zu stabilem und intuitivem Code

Vom Traum einer langlebigen Softwarearchitektur


Eine langlebig existierende Software ist wohl jedermanns Traum, aber oft nicht Realität. Mit der Verwendung von drei einfachen Methoden ist es möglich, sich eine Architektur zu erschaffen, die eine stabile und klare Linie im gesamten Projekt hält – und wenn einmal etwas falsch läuft, fällt ein Fehler sofort auf. Welche Methoden das sind, zeigt dieser Artikel.

Wer kennt es nicht: Mit hohen Ambitionen und Erwartungen startet man das neue Projekt. Dieses Mal wird alles besser, schöner, schneller, einfacher und zugleich intuitiver im Bereich der Softwarearchitektur. Meist funktioniert das zu Beginn gut, doch irgendwann kommt der Punkt, an dem der Druck zur Fertigstellung immer größer wird und bei Bugs vermehrt auf die Anbringung eines Pflasters Wert gelegt wird als darauf, die eigentliche Wunde zu heilen. Und somit wird die Software Schritt für Schritt verflochtener, komplexer und schwieriger zu Warten. Aber was soll’s, das nächste Projekt wird besser … oder? Wer ehrlich zu sich selbst ist, wird dieses Problem schon öfter im Arbeitsalltag oder in Projektteams erlebt haben. Doch wie kann bereits während der Entwicklungsphase auf zukünftig Probleme eingegangen werden, wie können schon jetzt die Grundlagen gelegt werden, diese mit weniger Aufwand zu beheben? Beginnen kann man dabei schon in der frühen Projektphase mit Einsatz der Immutability, was auch die erste der drei Methoden darstellt, die wir uns in diesem Artikel näher ansehen werden.

Immutability

Vermeidung von Side Effects fängt bereits auf tiefster Ebene an – und zwar mit dem Ansatz der Immutability. Die Unveränderlichkeit, wie sie auf Deutsch heißt, besagt, dass sich Objekte in Bezug auf ihre Eigenschaften nicht mehr ändern sollen. Dieser Ansatz ist gar nicht so untypisch für unsere Welt. Uns allen sollte bewusst sein, dass wir zum Großteil keine neuen Erfindungen im Bereich der Programmierungen schaffen, sondern meist oft nur unsere echte Welt als digitales Abbild widerspiegeln. Wenn man nun anhand unserer realen Welt eine Klasse Person modelliert, ergibt es dann Sinn, ein setBirthday anzubieten? Oder sollte das nur einmalig im Konstruktor stattfinden? Wohl eher Letzteres! Es ergibt einfach keinen Sinn, dass ein und dieselbe Person plötzlich ein anderes Geburtsdatum hat. Und das lässt sich womöglich auf noch ganz viele weitere Eigenschaften unserer Person anwenden (Geburtsort, Herkunft etc.). Könnte das also ein Anzeichen dafür sein, dass die meisten Eigenschaften unveränderlich im Konstruktor übergeben werden und unsere Person so gut wie keine Setter mehr besitzt?

Dies bedeutet nicht, dass man keine Setter mehr erstellen sollte, jedoch ist es ein langfristig dankbarer Weg, auf möglichst viele davon zu verzichten und den größeren Teil der Eigenschaften über den Konstruktor zu setzen. Doch was macht man, wenn sich tatsächlich eine dieser nicht veränderbaren Eigenschaften verändern möchte? Dafür entfernen wir uns von unserer Beispielperson und betrachten mit einem abstrakteren Beispiel zwei einfache Wege: Entweder handelt es sich bei unserer Anforderung um eine kontrolliert veränderbare Eigenschaft, womöglich ein Hashwert, dann könnte es die Funktion regenerateHash() geben, um das entsprechend des OOP-Ansatzes sauber durchführen zu lassen. Oder man muss so ehrlich sein und erkennen, dass es sich bei Veränderung dieser Eigenschaft um eine neue Identität des Objekts handelt. Somit muss ein neues Objekt instanziiert werden. Gerade der Bereich der Neuerstellung mit einer Vielzahl an Konstruktorargumenten wirkt oftmals sehr zeitaufwendig und verleitet schnell dazu, erneute Setter einzuführen. Jedoch könnte man sich auch die einfache Frage stellen: „Wenn ich die Identität meines Objekts definiert erstelle, warum müsste ich es immer und immer wieder ändern und somit neu erstellen, um an mein Ziel zu gelangen? Was mache ich falsch bei meiner Modellierung?“

Und damit wird eigentlich relativ schnell klar, dass das Wesen „Entwickler“ gerne mal den einfacheren Weg geht, und schnell das globale Bild der gewünschten Architektur aus dem Auge verliert. Eine Person mit Geburtsdatum ist zwar nicht so weit hergeholt, aber was bedeuten diese theoretischen Ansätze nun für eine „echte“ Applikation? Nehmen wir an, wir haben einen einfachen HTTP-Client. Dieser ist über eine Factory in Bezug auf Connection Timeout, Exception Handling und Base URL korrekt konfiguriert. Nun verwenden wir diese exakte Instanz in unserer doch etwas längeren und suboptimalen Ablauflogik – damit sind viele if-Statements und Schleifen mit einer Länge von ein paar hundert Zeilen Code gemeint, also nichts, was man laut Lehrbuch macht, was aber in der Realität trotzdem vorkommt. Nun kann es sein, dass der obere Teil eines Algorithmus mit einem Request Timeout von maximal 20 Sekunden arbeiten solle, der Code weiter unten jedoch auf ein Maximum von 10 Sekunden reduziert werden muss und deshalb einfach den entsprechenden Setter des Timeouts verwendet. Wenn dann noch eine große Schleife über beide Teile gestülpt...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Gewinner-Teams

Wir bieten Lizenz-Lösungen für Teams jeder Größe: Finden Sie heraus, welche Lösung am besten zu Ihnen passt.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang