Modulare Softwarearchitektur – Vorteile anhand eines Textchatservers erklärt

Zu Beginn eines neuen Projekts steht der Softwareentwickler vor der Herausforderung, die Architektur des Programmcodes nachhaltig zu designen. Neben der leichten Wartung, der geringen Abhängigkeit von spezifischen Bibliotheken und unabhängigen Testmöglichkeiten, sollte auch die Lesbarkeit im Vordergrund einer erfolgreichen Softwarearchitektur stehen. Eine verkürzte Entwicklungsdauer für eine Erweiterung ist nur ein positiver Effekt der Strukturierung.
Unter Einhaltung von diversen Konzepten können die genannten Anforderungen erfüllt werden. Oftmals fällt in diesem Zusammenhang der Begriff „Clean Code“ mit dem dazugehörigen Prinzip „Trennung von Verantwortlichkeiten“. Nachfolgend stellen wir eine Möglichkeit vor, wie dieses Konzept auf die Implementierung eines Textchatservers angewendet werden kann.

Textchatserver

Zu den Aufgaben eines aktuellen Kundenprojekts zählte die Umsetzung eines Textchatserver, bei dem die Funktionsweise schnell verändert werden kann. Die sich wandelnden Anforderungen konnten mithilfe einer Modularität effektiv erfüllt werden.
Anders als bei einer monolithischen Architektur ist es mit einem modularen Aufbau möglich, z. B. voneinander unabhängig agierende Datenhaltungskonzepte einzusetzen, die keine Änderung am restlichen Quellcode erfordern. Die benannte Aufteilung in Module ist der architektonische Schwerpunkt dieses Textchatservers.

Grundlegend hat der Textchatserver zwei Aufgaben: Events annehmen und Events verteilen. Ein Event kann dabei eine Nachricht, aber auch eine Information über einen Chatbeitritt sein. Die Events durchlaufen während eines aktiven Chats mehrere Phasen: u. a. Serialisieren, Deserialisieren, Validieren, Persistieren und die Verteilung zu den Clients. Jede Phase wiederum verwendet unterschiedliche Technologien. Beispielsweise müssen mehrere Serialisierungsmechanismen unterstützt werden, da einige Chatclients ansonsten nicht kompatibel wären.

Modulaufteilung

Die Implementierung des Textchatservers haben wir mit der Programmiersprache Java umgesetzt und dabei den Quellcode in mehreren logischen Modulen separiert. Ab der Version 9 bietet Java mit dem „Project Jigsaw“ eine native Möglichkeit, Quellcode aufzuteilen. Für ältere Java Versionen können zur Modularisierung Build Tools verwendet werden, wie bspw. Maven oder Gradle.

Exemplarischer Aufbau der Implementierung

Die Abbildung visualisiert den exemplarischen Aufbau der Implementierung, welches sich an dem Facade Design Pattern orientiert. Das zentrale Modul common beinhaltet alle übergreifenden Komponenten des Systems. Die Besonderheit ist jedoch, dass dieses Modul keine konkrete Logik umsetzt, sondern überwiegend Interfaces beinhaltet, die entweder statisch während der Entwurfszeit oder dynamisch zur Laufzeit durch technologieabhängige Module ersetzt und dadurch implementiert werden. So ist in common das Interface MessageService mit den Methodensignaturen für get, create, update und delete definiert. Der Softwareentwickler hat anschließend die Möglichkeit, die Implementierung entsprechend der gewünschten Technologie umzusetzen. Für unseren Textchatserver haben wir ein separates Modul persistence-db erstellt, in dem sich der Quellcode befindet, um Events in einer Datenbank zu speichern. Das Modul hat eine Abhängigkeit in Richtung common und erbt vom Interface MessageService. Die entsprechenden Methoden werden anschließend in Bezug auf die Persistierung in einer Datenbank implementiert.
Insbesondere bei einer agilen Arbeitsweise ändern sich die Anforderungen an eine Softwarekomponente: Ein externer Service soll nun die Datenbank ersetzen. Die Abhängigkeit zur Datenbank ist durch die Modularität schnell aufzulösen. Lediglich ein neues Modul persistence-service mit der entsprechenden Implementierung des Interfaces MessageService erfüllt die neue Anforderung. Statt der vorherigen Datenbankverbindung werden nun Aufrufe zum externen Service gesendet. Eine weitere Anpassung des Quellcodes ist nicht erforderlich.

Nach einem ähnlichen Prinzip agieren die auf der Abbildung dargestellten Module communication-http, communication-mqtt, serialisation-json und serialisation-proto. Die Clients, die auf den Textchatserver zugreifen, müssen nicht zwangsläufig das gleiche Protokoll und die gleiche Serialisierungsform unterstützen. Wie in einem Baukastensystem können die benötigten Technologien in der Architektur mithilfe von Modulen hinzugefügt werden. In unserem Beispiel würde der Textchatserver die Protokolle HTTP, MQTT sowie die Serialisierungsformen JSON und Protocol Buffers unterstützen. Ist nun das Protokoll AMQP erforderlich, kann das entsprechende Modul implementiert und hinzugefügt werden.

Die bisher beschriebenen Module bilden in der Gesamtheit die Basis für die Software. Die abschließenden Module client-web und client-mobile greifen auf diese Basis zu und ergänzen die Implementierung in Richtung der Clients. Diese Module definieren und implementieren die erforderlichen Schnittstellen, um mit einem Webbrowser oder mit einer mobilen Anwendung zu kommunizieren. Auch hier sind, je nach Anforderung, weitere Module möglich. Abhängig vom Anwendungsfall ist es sinnvoll, die Module von mehreren Clients zu kombinieren.

Fazit

Die Architektur einer Softwarekomponente bildet den Grundbaustein, um spätere Anforderungen schnell und effizient umsetzen zu können. In dem beschriebenen Beispiel haben wir einen Textchatserver in eine Vielzahl von Modulen aufgeteilt. Unter Einhaltung von „Clean Code“ Prinzipien und diversen Entwurfsmuster konnten wir einen übersichtlichen Quellcode erstellen. Zudem fördert die gewonnene Modularität die Umsetzung unabhängiger Testmöglichkeiten.

Autor: Stefan Schomacker, Developer