Motivation: Warum Architektur?
Softwareprojekte beinhalten eine große Menge Code. Angenommen, wir schreiben den kompletten Code in eine Datei, dann verlieren wir sehr schnell die Übersicht, in welchem Teil jetzt genau was passiert.
Wir stoßen schon bei einigen Dutzend Zeilen Code auf ein grundlegendes Prinzip des Software Engineerings: “Separation of Concerns” (Nachzulesen z.B. auf CCD). Dieses grundlegende Prinzip weist mich als Software Engineer dazu an, Code entsprechend seiner Fachlichkeit zu trennen. Dabei sollen sich die einzelnen Fachlichkeiten möglichst wenig überschneiden. Der Code gewinnt Übersichtlichkeit, ist einfacher zu lesen, einzelne Teile des Codes können unabhängig getestet werden und vieles mehr.
Denken wir einen Schritt weiter und vergrößern unser Projekt um ein Vielfaches. Jetzt haben wir tausende bis zehntausende Zeilen Code. Das bedeutet in der Praxis, dass wir unseren Code vermutlich (und hoffentlich) in hunderte Dateien aufgeteilt haben. Plötzlich ist die Codebasis nicht mehr übersichtlich, nicht mehr einfach zu lesen und dank der wachsenden Komplexität ist sie vermutlich auch nicht mehr so einfach zu testen. Wie können wir dieses Problem nun mit Hilfe von “Separation of Concerns” lösen?
Der erste Schritt zur Erleuchtung ist, die Software in Module aufzuteilen. Die Module sind sehr abhängig davon, welche Art Projekt man hat. Hat man irgendeine Art Datenbankzugriff in seiner Anwendung, gibt es vermutlich ein Modul namens “DB”. Wenn man sehr viele Interaktionen mit mindestens einer Datenbank hat, kann es mehrere Datenbank-Module mit verschiedenen Größen und Komplexitäten geben. Denkbar ist hier zum Beispiel eine Trennung der Module “Kunden DB” und “Versicherungs DB” auf fachlicher Ebene. Aber auch auf technischer Ebene macht eine Trennung Sinn. So befinden sich gecachte Daten vermutlich auf anderen Technologien als das Data Warehouse.
Sind nun die einzelnen Module getrennt, stellt sich die Frage der Abhängigkeiten: Angenommen, wir haben nur 10 Module und diese rufen sich unkontrolliert gegenseitig auf. Wenn es keine feste Regelung gibt, welches Modul von welchem anderen abhängig sein darf, dann sieht der Abhängigkeitsgraph aus wie Spaghetti. Die gruseligste Gefahr einer solchen Struktur ist die Zyklusbildung. Von einem Zyklus sprechen wir, wenn ein Modul über mehrere Ecken indirekt von sich selbst abhängt.
Nicht erstrebenswerte \“Spaghetti\“-Architektur
Warum also Architektur?
Wir erhoffen uns von einer Softwarearchitektur Klarheit über die Trennung von Modulen und deren Abhängigkeiten zueinander.
Definition: Softwarearchitektur
Architektur ist einer dieser Begriffe, von dem die meisten eine Vorstellung haben, was er bedeutet. Aber fragt man zehn Menschen, bekommt man 11 verschiedene Antworten.. Der Begriff ist in der Praxis beliebig dehnbar. So kann man die Organisationsstruktur des Unternehmens und den Entscheidungsprozess von Architekturfragen mit in die Definition der “Softwarearchitektur” einschließen. Die korrekte Antwort auf die Definitionsfrage ist daher wohl “Softwarearchitektur ist das, was Softwarearchitektinnen und -architekten machen.”
Ich bin ein Freund von möglichst präzisen Definitionen. Wikipedia sagt zu Softwarearchitektur: “Software architecture refers to the fundamental structures of a software system and the discipline of creating such structures and systems. […] Software architecture is about making fundamental structural choices that are costly to change once implemented.” Wir reden im Bereich der Architektur (nach dieser Beschreibung) also von fundamentalen, schwer zu verändernden Strukturen und der Disziplin der Erzeugung dieser Strukturen. Der Umfang dieser Disziplin lässt sich wieder diskutieren. Zum Beispiel sollte man vermutlich die Begründungen von Architekturentscheidungen selbst mit in den Architekturbegriff fassen, damit die Motivationen einzelner Entscheidungen miteinander vereinbar sind. So kann verhindert werden, dass verschiedene Architekten im selben Projekt gegeneinander arbeiten.
Wer nach der Abgrenzung der Begriffe Software-Design, Architektur und Anforderungsanalyse sucht, wird enttäuscht sein. Architektur ist eine Art Design, aber es gibt keine klare Abgrenzung zwischen den Begriffen. So macht eine Architektin neben Architektur auch immer ein bisschen (lower level) Design und Anforderungsmanagement. Eine Entwicklerin macht selbst bei kleinen Aufgaben auch immer ein bisschen Architektur.
Wenn man so viel über Definitionen spricht und schreibt, vergisst man gerne mal wichtigere Fragen wie zum Beispiel \“Was macht eine gute Softwarearchitektur aus?\“
Und diese Frage zu beantworten, ist nicht so einfach.
Ich würde sagen \“Eine gute Softwarearchitektur ermöglicht den Entwicklern, selbst sehr spät in einem Projekt noch genauso produktiv zu sein wie am Anfang.\“
Architektur: Qualitätsmerkmale
Durchsucht man gängige Quellen, findet man heutzutage meistens die folgenden Qualitätsanforderungen an Softwarearchitekturen: Die Architektur soll den aktuellen Zustand des Projekts gut beschreiben und darüber hinaus die Umsetzungen zukünftiger Anforderungen so einfach wie möglich machen.
Ich möchte die Antwort auf die Frage nach Qualitätsmerkmalen aus einer etwas anderen Perspektive darstellen. Dabei stelle man sich das Softwaresystem auf einem Zeitstrahl richtung Zukunft vor. Kurzfristig müssen einige Menschen den Code lesen und das System verstehen. Mittelfristig muss das System um neue Features erweitert werden. Langfristig müssen bestehende Features oder technische Details (wie Datenbanken oder im schlimmsten Fall Frameworks) verändert werden, neue Mitarbeiter müssen sich einarbeiten und vieles mehr. Während des kompletten Prozesses brauchen wir Sicherheit, dass das Gesamtsystem funktioniert. Dafür müssen wir es stets überprüfen können. Diese Sicherheit erlangt man in der Regel durch manuelle und automatisierte Tests.
Mit dieser Klassifizierung ist es einfacher von außen zu beurteilen, wie gut eine Architektur ist:
Woran erkenne ich eine schlechte Architektur von außen?
Woran erkenne ich eine gute Architektur von außen?
- Verstehen: Ein neuer Entwickler kommt ins Team und hat Schwierigkeiten, das System zu verstehen.
- Erweitern: Im Laufe eines Projekts dauert die Entwicklung neuer Features immer länger. Unter Umständen werden Features sogar als “Inkompatibel zur Architektur” abgelehnt.
- Verändern: Bugfixes kosten viel Zeit. Ein komplettes Team ist vergleichsweise lange ausgelastet, nur um ein bereits bestehendes Feature an leicht veränderte Anforderungen anzupassen.
- Überprüfen: Mit der Implementierung eines neuen Features gehen alte Features kaputt, die bisher funktioniert haben.
- Verstehen: Eine neue Entwicklerin kann bereits im ersten Sprint neue Features implementieren, weil das Einlesen in den Code sehr schnell geht.
- Erweitern: Die Geschwindigkeit des Teams ist konstant. Die Implementierung eines Features dauert am Ende des Projekts genau so lang wie am Anfang.
- Verändern: Die Veränderung eines bestehenden Features dauert signifikant kürzer als die ursprüngliche Implementierung.
- Überprüfen: Bugs sind selten. Die meisten Bugs treten in den aktuellsten Features auf. Was einmal funktioniert hat, geht nicht so leicht kaputt.
Ausblick
Mit einer sauberen und gut geplanten Softwarearchitektur können viele potentielle Probleme bereits vor Entstehung verhindert werden. Es zahlt sich aus, die Zeit vor der eigentlichen Entwicklung zu investieren und sich darüber Gedanken zu machen.
Damit man nicht jedes Mal das Rad neu erfinden muss, kann man sich einer Vielzahl von Referenzarchitekturen wie einer “traditionellen” Schichtenarchitektur, der hexagonalen oder auch serviceorientierten Architektur bedienen. Auf diese und welche Architekturen wir bei Netfonds verwenden, wird in einem kommenden Beitrag näher eingegangen.
Bild: Canva, draw.io