Entwurf und Architektur
In dieser Lerneinheit tauchst du in die Prinzipien des qualitätsgetriebenen Softwareentwurfs (Quality-Driven Design) ein. Du lernst, wie du Softwarearchitektur und Systemdesign von Anfang an auf wichtige Qualitätsmerkmale wie Wartbarkeit, Performance und Sicherheit ausrichtest. Diese Kenntnisse helfen dir dabei, robuste und zukunftssichere Softwarelösungen zu entwickeln, die sich später leichter anpassen und erweitern lassen.
Einführung
Stell dir vor: Du bist Teil eines Entwicklerteams, das eine E-Commerce-Plattform baut. Nach sechs Monaten intensiver Arbeit zeigt sich das Problem: Die Seite wird bei vielen gleichzeitigen Nutzern quälend langsam. Jedes neue Feature erfordert Änderungen an dutzenden Stellen. Und die Codebasis? Ein undurchschaubares Chaos.

Wie hätte das Team diese Probleme vermeiden können?
Die Antwort: Qualitätsgetriebener Entwurf. Wer von Anfang an Wartbarkeit, Performance und Skalierbarkeit in den Mittelpunkt stellt, spart sich später teure Nachbesserungen und frustrierende Debugging-Sessions.
Lernziele
Nach dieser Lerneinheit kannst du:
- Die Prinzipien des Quality-Driven Design erklären und anwenden
- Architekturmuster (Layered, Microservices, Event-Driven, Client-Server) unterscheiden und situativ auswählen
- Methoden zur Architekturbewertung (ATAM, SAAM, CBAM) beschreiben
- Code Smells erkennen und durch Refactoring beheben
Überleitung
Das Chaos der E-Commerce-Plattform hätte sich vermeiden lassen, wenn das Team von Beginn an die Qualität in den Mittelpunkt gestellt hätte.
Genau das macht der qualitätsgetriebene Entwurf. Schauen wir uns an, was dahinter steckt.
Was ist Quality-Driven Design?
Quality-Driven Design (QDD) ist ein Ansatz, bei dem Qualitätsmerkmale wie Wartbarkeit, Performance und Sicherheit von Anfang an in den Entwurfsprozess einbezogen werden.
Statt Qualität erst am Ende zu prüfen, wird sie zum Leitprinzip jeder Architekturentscheidung.
Der Grundgedanke: Fehler im Entwurf sind später teuer zu beheben. Je früher Qualitätsanforderungen berücksichtigt werden, desto kostengünstiger und stabiler wird die Software.
Schlüsselprinzipien von QDD
Quality-Driven Design folgt vier zentralen Prinzipien, die den gesamten Entwicklungsprozess leiten:
| Prinzip | Beschreibung |
|---|---|
| Frühzeitige Integration | Qualitätsanforderungen werden von Projektbeginn an gesammelt und priorisiert |
| Systematische Bewertung | Die Architektur wird regelmäßig geprüft, ob sie die Qualitätsziele erfüllt |
| Iteratives Verfeinern | Erkenntnisse aus Bewertungen fließen in Verbesserungen ein |
| Best Practices nutzen | Bewährte Muster und Techniken werden gezielt eingesetzt |
Diese Prinzipien wirken zusammen: Du startest mit klaren Qualitätszielen, überprüfst regelmäßig den Fortschritt und passt die Architektur bei Bedarf an.
Architekturmuster - Überblick
Architekturmuster sind bewährte Lösungsansätze für wiederkehrende Probleme beim Systemdesign. Sie definieren, wie Komponenten organisiert und miteinander verbunden werden.
Warum sind sie wichtig?
- Sie fördern die Kommunikation im Team durch gemeinsames Vokabular
- Sie erleichtern Architekturentscheidungen
- Sie unterstützen gezielt bestimmte Qualitätsattribute
Die vier wichtigsten Muster schauen wir uns jetzt an.
Layered Architecture (Schichtenarchitektur)
Die Schichtenarchitektur trennt Verantwortlichkeiten in klar abgegrenzte Schichten:
| Schicht | Aufgabe | Beispiel |
|---|---|---|
| Präsentationsschicht | Benutzeroberfläche | HTML/CSS, React, Angular |
| Geschäftslogikschicht | Fachliche Regeln | Bestellvalidierung, Preisberechnung |
| Datenzugriffsschicht | Datenbankzugriff | SQL-Queries, ORM |
Stärken: Gute Wartbarkeit, einfaches Testen einzelner Schichten, klare Struktur
Einschränkung: Bei sehr großen Systemen kann die strikte Schichtung zu Performance-Overhead führen.
Microservices Architecture
Bei Microservices wird eine Anwendung in kleine, unabhängige Services aufgeteilt. Jeder Service ist für eine spezifische Geschäftsfunktion zuständig.
Beispiel E-Commerce:
- Produkt-Service: Verwaltet Produktkatalog
- Warenkorb-Service: Verwaltet Warenkörbe
- Bestell-Service: Verarbeitet Bestellungen
- User-Service: Authentifizierung und Profile
Stärken: Hohe Skalierbarkeit, unabhängiges Deployment, Technologievielfalt möglich
Einschränkung: Höhere Komplexität bei Kommunikation, Monitoring und Debugging.
Event-Driven Architecture
Die ereignisgesteuerte Architektur organisiert Software um die Verarbeitung von Events (Ereignissen).
Ablauf:
- Ein Producer löst ein Event aus (z.B. “Bestellung aufgegeben”)
- Das Event wird an einen Event Bus gesendet
- Consumer reagieren auf das Event (z.B. Lager aktualisieren, Email senden)
Stärken: Hohe Reaktionsfähigkeit, lose Kopplung zwischen Komponenten, gute Skalierbarkeit
Einschränkung: Komplexeres Debugging, da Ereignisse asynchron verarbeitet werden.
Client-Server Architecture
Die klassische Client-Server-Architektur trennt zwischen Anfragenden (Clients) und Dienstanbietern (Servern).
Typisches Szenario:
- Client: Webbrowser, Mobile App
- Server: Webserver, API-Server, Datenbankserver
Stärken: Klare Rollenverteilung, zentralisierte Datenhaltung, einfache Skalierung durch mehr Server
Einschränkung: Server ist Single Point of Failure, wenn nicht redundant ausgelegt.
Architekturmuster - Zusammenfassung
Die vorgestellten Architekturmuster haben jeweils ihre Stärken und eignen sich für unterschiedliche Szenarien. Die Wahl des richtigen Musters hängt von den Qualitätszielen deines Projekts ab.
| Muster | Primäres Qualitätsziel | Typischer Einsatz |
|---|---|---|
| Layered | Wartbarkeit, Testbarkeit | Klassische Webanwendungen, Unternehmenssoftware |
| Microservices | Skalierbarkeit, Unabhängigkeit | Große, verteilte Systeme, Cloud-native Apps |
| Event-Driven | Reaktionsfähigkeit, Entkopplung | IoT, Echtzeit-Systeme, Message-Verarbeitung |
| Client-Server | Zentralisierung, Skalierbarkeit | Web-Apps, Datenbank-Anwendungen |
Wichtig: In der Praxis werden Muster oft kombiniert. Eine E-Commerce-Plattform könnte Microservices mit Event-Driven-Kommunikation nutzen.
Warum Architekturen bewerten?
Eine Architektur zu entwerfen ist nur der erste Schritt. Um sicherzustellen, dass sie die Qualitätsziele erfüllt, muss sie systematisch bewertet werden.
Gründe für Architekturbewertung:
- Risiken frühzeitig erkennen
- Trade-offs zwischen Qualitätszielen verstehen
- Verbesserungspotenziale identifizieren
- Stakeholder-Erwartungen abgleichen
Die drei etabliertesten Methoden sind ATAM, SAAM und CBAM.
ATAM - Architecture Tradeoff Analysis Method
ATAM wurde vom Software Engineering Institute (Carnegie Mellon University) entwickelt. Der Name verrät den Kern: Es geht um Trade-offs zwischen Qualitätsattributen.
Jede Architekturentscheidung hat Vor- und Nachteile. ATAM macht diese sichtbar.
Beispiel Trade-off: Mehr Verschlüsselung erhöht die Sicherheit, kann aber die Performance reduzieren.
ATAM hilft, solche Konflikte zu identifizieren und bewusst zu entscheiden.
Die 9 Schritte der ATAM-Methode
ATAM wird typischerweise in zwei Phasen durchgeführt. Phase 1 findet mit dem Kernteam statt und dient der ersten Analyse. Phase 2 bezieht weitere Stakeholder ein und erweitert die Perspektive.
Warum zwei Phasen? In Phase 1 verstehen die Architekten das System im Detail. In Phase 2 bringen Stakeholder neue Szenarien ein, die das Team möglicherweise übersehen hat. Diese Kombination stellt sicher, dass sowohl technische als auch geschäftliche Aspekte berücksichtigt werden.
| Phase | Schritt | Beschreibung |
|---|---|---|
| Phase 1 | 1. ATAM vorstellen | Methode den Stakeholdern erklären |
| 2. Business Drivers | Geschäftsziele und Anforderungen präsentieren | |
| 3. Architektur vorstellen | Architekt präsentiert das Design | |
| 4. Architekturansätze identifizieren | Verwendete Muster und Taktiken dokumentieren | |
| 5. Utility Tree erstellen | Qualitätsattribute priorisieren und Szenarien zuordnen | |
| 6. Analyse (erste Runde) | Szenarien gegen Architektur testen | |
| Phase 2 | 7. Weitere Szenarien sammeln | Mit mehr Stakeholdern neue Szenarien erarbeiten |
| 8. Analyse (zweite Runde) | Erweiterte Analyse | |
| 9. Ergebnisse präsentieren | Risiken, Trade-offs, Empfehlungen dokumentieren |
Typischer Aufwand: Phase 1 dauert etwa einen Tag, Phase 2 zwei weitere Tage. Für kleinere Projekte kann ATAM auch in verkürzter Form durchgeführt werden.
Architektur Trade-offs - Security vs. Performance
Beispiel 1: Security vs. Performance
- Szenario: E-Commerce mit hohem Sicherheitsbedarf
- Trade-off: Jede Anfrage verschlüsseln und authentifizieren
- Vorteil: Maximale Sicherheit
- Nachteil: Jede Anfrage dauert 50-100ms länger
- Lösung: Kritische Operationen (Zahlung) stark absichern, öffentliche Inhalte (Produktliste) weniger
Architektur Trade-offs - Konsistenz vs. Verfügbarkeit
Beispiel 2: Konsistenz vs. Verfügbarkeit
- Szenario: Verteilte Datenbank
- Trade-off: Immer aktuelle Daten vs. System auch bei Netzwerkproblemen verfügbar
- Lösung: Für Likes/Kommentare reicht “Eventual Consistency”, für Zahlungen braucht man starke Konsistenz
Das ist das bekannte CAP-Theorem: Consistency, Availability, Partition Tolerance - nur zwei von drei sind gleichzeitig erreichbar.
SAAM - Software Architecture Analysis Method
SAAM war die erste dokumentierte Architektur-Analysemethode (Mitte der 1990er) und ist der Vorläufer von ATAM. Der Fokus liegt auf der Bewertung der Modifizierbarkeit einer Architektur.
SAAM nutzt szenariobasierte Evaluierung und unterscheidet zwei Arten von Szenarien:
- Direct Scenarios: Anforderungen, die die Architektur direkt unterstützt (keine Änderungen nötig)
- Indirect Scenarios: Anforderungen, die Architektur-Änderungen erfordern
Beispiel:
- Direct: “Produkte anzeigen” - funktioniert bereits
- Indirect: “Multi-Währungs-Support” - erfordert Architekturanpassungen
Je mehr Indirect Scenarios es gibt, desto geringer ist die Modifizierbarkeit der Architektur. SAAM hilft damit, potenzielle Änderungsaufwände früh zu erkennen.
CBAM - Cost Benefit Analysis Method
CBAM erweitert ATAM um eine wirtschaftliche Perspektive. Architekturentscheidungen werden nach Kosten und Nutzen bewertet.
Kernfragen:
- Was kostet die Umsetzung einer Architekturvariante?
- Welchen geschäftlichen Nutzen bringt sie?
- Wie ist der Return on Investment (ROI)?
Anwendung: CBAM wird nach einer ATAM-Analyse eingesetzt, wenn mehrere Architekturoptionen zur Auswahl stehen und die Investition begründet werden muss.
Was ist Refactoring?
Refactoring ist ein systematischer Prozess zur Verbesserung des Codes, ohne sein externes Verhalten zu ändern.
Der Code macht nachher genau dasselbe wie vorher, aber er ist sauberer, verständlicher und wartbarer.
Ziele:
- Bessere Lesbarkeit für andere Entwickler
- Einfachere Wartung und Fehlersuche
- Vorbereitung für neue Features
- In manchen Fällen: Performance-Verbesserung
Wann sollte Refactoring durchgeführt werden?
Refactoring ist keine einmalige Aktion, sondern ein kontinuierlicher Prozess. Die Frage ist nicht ob, sondern wann und wie oft.
| Zeitpunkt | Begründung |
|---|---|
| Bei Code Smells | Wenn der Code Anzeichen von schlechtem Design zeigt |
| Vor Erweiterungen | Bevor neue Features eingebaut werden, die Codebasis aufräumen |
| Nach Fertigstellung | Nach einem Feature den Code “polieren” |
| Regelmäßig | Als Teil der normalen Entwicklung, nicht als separates Projekt |
Wichtig: Vor dem Refactoring müssen Tests existieren, die das korrekte Verhalten sicherstellen. Ohne Tests weißt du nicht, ob du beim Umbau etwas kaputt gemacht hast.
Code Smells - Überblick
Code Smells sind Hinweise auf potenzielle Probleme im Code. Sie sind keine Fehler im eigentlichen Sinne, aber Warnsignale für schlechtes Design, das langfristig zu Problemen führen kann.
Der Begriff stammt von Kent Beck und wurde durch Martin Fowlers Buch “Refactoring” populär.
Die wichtigsten Code Smells, die du kennen solltest:
- Duplicated Code - Gleicher Code an mehreren Stellen
- Long Method - Methoden mit zu vielen Zeilen
- Large Class - Klassen mit zu vielen Verantwortlichkeiten
- Magic Numbers - Hardcodierte Zahlen ohne Erklärung
Schauen wir uns einige davon genauer an.
Code Smell - Duplicated Code
Problem: Dieselbe Logik existiert an mehreren Stellen. Änderungen müssen überall nachgezogen werden.
Beispiel: Email-Validierung in zwei Methoden:
// In der Registrierung:
public void registriere(String email, String passwort) {
if (email == null || email.indexOf("@") < 0) {
throw new IllegalArgumentException("Ungültige Email");
}
// ... weitere Logik
}
// Im Profil-Update (identische Prüfung):
public void aktualisiereEmail(String neueEmail) {
if (neueEmail == null || neueEmail.indexOf("@") < 0) {
throw new IllegalArgumentException("Ungültige Email");
}
// ... weitere Logik
}Erklärung des Codes
Dieser Code zeigt das Problem von dupliziertem Code.
-
Die Validierungslogik ist identisch: In beiden Methoden wird exakt dieselbe Prüfung durchgeführt:
email == null || email.indexOf("@") < 0. Das prüft, ob die Email leer ist oder kein @-Zeichen enthält. -
Warum ist das problematisch? Stell dir vor, du möchtest die Validierung verbessern (z.B. auch auf einen Punkt nach dem @ prüfen). Du musst jetzt an beiden Stellen ändern. Bei größeren Projekten mit dutzenden solcher Stellen vergisst man leicht eine.
-
Die Lösung: Extrahiere die Validierung in eine eigene Methode:
private void validiereEmail(String email) {
if (email == null || email.indexOf("@") < 0) {
throw new IllegalArgumentException("Ungültige Email");
}
}Jetzt rufst du nur noch validiereEmail(email) auf. Änderungen sind zentral an einer Stelle möglich.
Code Smell - Long Method und Magic Numbers
Long Method
Problem: Eine Methode macht zu viel und ist schwer zu verstehen.
Faustregel: Methoden mit mehr als 20-30 Zeilen oder mehr als einer Verantwortlichkeit sind verdächtig.
Lösung: In kleinere, fokussierte Methoden aufteilen (Extract Method).
Magic Numbers
Problem: Hardcodierte Zahlen ohne Erklärung.
// BAD: Was bedeutet 1?
if (user.getStatus() == 1) {
aktiviereBenutzer(user);
}
// GOOD: Konstante mit sprechendem Namen
public static final int STATUS_ACTIVE = 1;
if (user.getStatus() == STATUS_ACTIVE) {
aktiviereBenutzer(user);
}Erklärung des Codes
Dieser Code zeigt das Problem der “Magic Numbers” und deren Lösung.
-
if (user.getStatus() == 1)(BAD): Im ersten Beispiel wird der Status des Benutzers mit der Zahl1verglichen. Das Problem: Niemand weiß auf Anhieb, was1bedeutet. Ist das “aktiv”? “Gesperrt”? “Premium”? Man muss raten oder in der Dokumentation suchen. -
public static final int STATUS_ACTIVE = 1;(GOOD): Hier wird eine Konstante definiert. Das Schlüsselwortfinalbedeutet, dass der Wert nicht mehr geändert werden kann.staticmacht die Konstante klassenübergreifend verfügbar. -
if (user.getStatus() == STATUS_ACTIVE): Jetzt ist sofort klar, was geprüft wird: Ist der Benutzer aktiv? Der Code dokumentiert sich selbst.
Warum ist das wichtig? Bei “Magic Numbers” muss man raten, was die Zahl bedeutet. Konstanten dokumentieren sich selbst und verhindern Fehler bei Änderungen.
Refactoring-Technik - Extract Method (Vorher)
Die häufigste Refactoring-Technik: Code-Blöcke in eigene Methoden auslagern.
Vorher: Eine Methode mit mehreren Verantwortlichkeiten:
public void verarbeiteBestellung(Bestellung bestellung) {
// Validierung
if (bestellung.getProdukte().isEmpty()) {
throw new IllegalArgumentException("Keine Produkte");
}
if (bestellung.getKunde() == null) {
throw new IllegalArgumentException("Kein Kunde");
}
// Preisberechnung
double summe = 0;
for (Produkt p : bestellung.getProdukte()) {
summe += p.getPreis() * p.getMenge();
}
// Speicherung
database.save(bestellung);
emailService.sendeBestaetigung(bestellung);
}Erklärung des Codes
Diese Methode macht drei verschiedene Dinge:
-
Validierung (Zeilen 2-7): Zuerst wird geprüft, ob die Bestellung gültig ist. Hat sie Produkte? Ist ein Kunde zugeordnet? Bei Fehlern wird eine Exception geworfen.
-
Preisberechnung (Zeilen 9-12): Eine Schleife iteriert durch alle Produkte und berechnet die Gesamtsumme: Preis mal Menge für jedes Produkt.
-
Speicherung (Zeilen 14-15): Die Bestellung wird in der Datenbank gespeichert und eine Bestätigungsmail wird versendet.
Das Problem: Diese Methode verletzt das Single Responsibility Principle. Sie hat drei Verantwortlichkeiten. Wenn sich die Preisberechnung ändert (z.B. Rabatte), muss man in dieser großen Methode suchen. Tests werden kompliziert, weil man nicht einzelne Teile isoliert testen kann.
Extract Method - Nachher
Nachher: Dieselbe Funktionalität, aber aufgeteilt in fokussierte Methoden:
public void verarbeiteBestellung(Bestellung b) {
validiereBestellung(b);
double summe = berechneGesamtpreis(b);
b.setGesamtpreis(summe);
speichereBestellung(b);
}
private void validiereBestellung(Bestellung b) {
if (b.getProdukte().isEmpty())
throw new IllegalArgumentException("Keine Produkte");
if (b.getKunde() == null)
throw new IllegalArgumentException("Kein Kunde");
}
private double berechneGesamtpreis(Bestellung b) {
double summe = 0;
for (Produkt p : b.getProdukte())
summe += p.getPreis() * p.getMenge();
return summe;
}
private void speichereBestellung(Bestellung b) {
database.save(b);
emailService.sendeBestaetigung(b);
}Erklärung des Codes
Der Code wurde in vier separate Methoden aufgeteilt:
-
verarbeiteBestellung()(Zeilen 1-6): Die Hauptmethode ist jetzt eine “Koordinator”-Methode. Sie ruft nur noch andere Methoden auf und liest sich wie eine Checkliste: validieren, berechnen, Preis setzen, speichern. -
validiereBestellung()(Zeilen 8-12): Diese Methode hat genau eine Aufgabe: Prüfen, ob die Bestellung gültig ist. Sie istprivate, weil sie nur intern verwendet wird. -
berechneGesamtpreis()(Zeilen 14-19): Berechnet nur den Gesamtpreis und gibt ihn alsdoublezurück. Durch den Rückgabewert ist klar, was die Methode macht. -
speichereBestellung()(Zeilen 21-24): Kümmert sich um die Persistenz: Datenbank-Speicherung und Email-Versand.
Die Vorteile:
- Lesbarkeit: Die Hauptmethode erklärt sich selbst.
- Testbarkeit: Jede Methode kann einzeln getestet werden.
- Wartbarkeit: Änderungen an der Preisberechnung betreffen nur
berechneGesamtpreis(). - Wiederverwendbarkeit:
berechneGesamtpreis()könnte auch an anderer Stelle genutzt werden.
Zusammenfassung
Zusammenfassung
Quality-Driven Design stellt Qualitätsmerkmale wie Wartbarkeit, Performance und Sicherheit von Anfang an in den Mittelpunkt des Entwurfsprozesses. Die vier Schlüsselprinzipien - frühzeitige Integration, systematische Bewertung, iteratives Verfeinern und Nutzung von Best Practices - sorgen dafür, dass Qualität kein nachträglicher Gedanke ist, sondern jede Architekturentscheidung leitet.
Architekturmuster bieten bewährte Lösungen für wiederkehrende Designprobleme:
| Muster | Stärke | Typischer Einsatz |
|---|---|---|
| Layered | Wartbarkeit, klare Trennung | Klassische Webanwendungen |
| Microservices | Skalierbarkeit, unabhängiges Deployment | Cloud-native, große Systeme |
| Event-Driven | Reaktionsfähigkeit, lose Kopplung | Echtzeit-Systeme, IoT |
| Client-Server | Zentralisierung, einfache Skalierung | Web-Applikationen |
Architekturbewertung macht Trade-offs sichtbar und hilft, Risiken frühzeitig zu erkennen. ATAM identifiziert Konflikte zwischen Qualitätszielen durch systematische Szenario-Analyse. SAAM bewertet die Modifizierbarkeit anhand von Direct und Indirect Scenarios. CBAM ergänzt die wirtschaftliche Perspektive mit Kosten-Nutzen-Analyse.
Refactoring verbessert die Codequalität kontinuierlich, ohne das externe Verhalten zu ändern. Code Smells wie Duplicated Code, Long Methods und Magic Numbers sind Warnsignale, die auf Refactoring-Bedarf hindeuten. Die Extract-Method-Technik ist das wichtigste Werkzeug, um große Methoden in fokussierte, wiederverwendbare Einheiten aufzuteilen und so das Single Responsibility Principle umzusetzen.
Ausblick
In der nächsten Lerneinheit Implementierung und Coding lernst du, wie du Coding Standards einsetzt, Code durch statische Analyse prüfst und Code Reviews effektiv durchführst.