Softwarearchitektur

Stefan Winter

Ludwig-Maximilians-Universität München

Folien online

Überblick und Lernziele

  • Was ist interne Qualität und “Cruft”?
  • Wie beeinflusst Cruft die Entwicklungseffizienz?
  • Wie beeinflusst Softwarearchitektur Cruft?
  • Weshalb braucht man “Architekturmuster”?

Software ohne Architektur


© Manu Cornet, License: CC BY-NC-ND 3.0, Source: bonkersworld.net

  • Bauarbeiten am grünen Haus
  • Wie viele Häuser sind direkt mit dem grünen Haus verbunden?
  • Wie viele Pfade zwischen dem blauen und dem braunen Haus durch das grüne Haus?
  • Wie viele Pfade insgesamt zwischen den Häusern und wie viele durch das grüne Haus?

Keine Architektur → schwer verständlich → lange Umsetzungszeiten für Änderungen

“Technical Debt” / “Cruft”

Zwei Arten der Softwarequalität:

  • Externe Softwarequalität: Software erfüllt Anforderungen im Betrieb
  • Interne Softwarequalität: Software ist leicht änderbar (ergo, wartbar und erweiterbar), da verständlich

Technical Debt / Cruft: Mangelnde interne Qualität

Konsequenzen von Cruft


© Martin Fowler, Source: Is high quality software worth the cost?


Hohe (interne) Qualität → geringere Wartungs- und Erweiterungskosten

Spannungsfeld Kosten/Qualität?


© Martin Fowler, Source: Is high quality software worth the cost?

  • Initial langsamere Entwicklung → höhere Kosten
  • Amortisiert durch schnellere inkrementelle Entwicklung

Code-Beispiel: Bestellsystem

OrderService.java
public double checkout(Order order) {

    double total = 0;

    for (Item item : order.items) {
        total += item.price;
    }

    if (order.customer.isPremium()) {
        total *= 0.9;
    }

    Database.save(order);
    Email.send(order.customer.email, 
               "Order placed!");

    return total;
}
PaymentService.java
public void validatePayment(Order order, 
                            double paidAmount) {
    double total = 0;

    for (Item item : order.items) {
        total += item.price;
    }

    if (order.customer.isPremium()) {
        total *= 0.9;
    }

    if (total != paidAmount) {
        throw new IllegalStateException("Invalid payment");
    }
}
InvoiceService.java
public double generateInvoice(Order order) {
    
    double total = 0;

    for (Item item : order.items) {
        total += item.price;
    }

    if (order.customer.isPremium()) {
        total *= 0.9;
    }

    return total;
}

Code-Beispiel: Änderung – Black Friday

30% Rabatt, nur am Black Friday! 🤑

OrderService.java
public double checkout(Order order, 
                       boolean isBlackFriday) {

    double total = 0;

    for (Item item : order.items) {
        total += item.price;
    }

    if (order.customer.isPremium()) {
        total *= 0.9;
    }

    if (isBlackFriday) {
        total *= 0.7;
    }

    Database.save(order);
    Email.send(order.customer.email, 
               "Order placed!");

    return total;
}
PaymentService.java
public void validatePayment(Order order, 
                            double paidAmount, 
                            boolean isBlackFriday) {
    double total = 0;

    for (Item item : order.items) {
        total += item.price;
    }

    if (order.customer.isPremium()) {
        total *= 0.9;
    }

    if (isBlackFriday) {
        total *= 0.7;
    }

    if (total != paidAmount) {
        throw new IllegalStateException("Invalid payment");
    }
}
InvoiceService.java
public double generateInvoice(Order order) {


    double total = 0;

    for (Item item : order.items) {
        total += item.price;
    }

    if (order.customer.isPremium()) {
        total *= 0.9;
    }

    // BUG: Black Friday discount forgotten

    return total;
}

Microservice-orientiertere Architektur

OrderService.java




public double checkout(Order order) {

    double total = 0;

    for (Item item : order.items) {
        total += item.price;
    }

    if (order.customer.isPremium()) {
        total *= 0.9;
    }

    Database.save(order);
    Email.send(order.customer.email, 
               "Order placed!");

    return total;
}
OrderService.java (revised)
private final PricingService pricing;
private final OrderRepository repo;
private final NotificationService notifier;

public double checkout(Order order) {

    double total = pricing.calculate(order);
    
    
    
    
    
    
    
    
    
    repo.save(order);
    notifier.notify(order);
    
    return total;
}
PricingService.java
private final List<DiscountPolicy> discounts;

public double calculate(Order order) {
    double total = 0;

    for (Item item : order.items) {
        total += item.price;
    }
    
    for (DiscountPolicy discount : discounts) {
        total = discount.apply(total, order);
    }
    return total;
}

Beobachtungen aus dem Beispiel

  • Geeignete Architektur erleichtert Änderungen 👍
  • Ungeeignete in geeignete Architektur zu überführen ist aufwändig 👎

→ Architekturentscheidung früh im Entwicklungsprozess

→ Wie entscheidet man bevor Architekturprobleme auftreten? 🤔

Architekturmuster (“Patterns”)

Viele verbreitete Architekturen:

  • Microservices: Siehe Beispiel
  • Layers: Stufenweise Abstraktion, z.B. Netzwerkprotokoll-Stack
  • Pipes and Filters: Sequenzielle Datentransformation, z.B. Compiler
  • Model-View-Controller (MVC): Trennung von Daten/Repräsentation/Änderung, z.B. Webanwendung

Eignung hängt vom Anwendungsfall ab

Vorteile von Architekturmustern

  • Kodieren jahrzehntelange Domänenerfahrung
  • Verbreitete Kenntnis bei Entwicklern → De-Facto Standards
    • Kommunikation
    • Einarbeitung in bestehende Systeme
  • Z.T. Umsetzung in Frameworks (z.B. MVC in Rails, Django, Spring MVC)

Zusammenfassung 🏁

  • Was ist interne Qualität und “Cruft”?
  • Wie beeinflusst Cruft die Entwicklungseffizienz?
  • Wie beeinflusst Softwarearchitektur Cruft?
  • Weshalb braucht man “Architekturmuster”?

Ausblick 🔭

Ergänzungen und Anknüpfungspunkte:

  • Detaillierte Diskussion verbreiteter Architekturmuster mit Anwendungsbeispielen
  • Kursprojekt: Interaktives Daten-Dashboard mit MVC-Framework
  • Kritische Reflexion: Objektive Güte versus Normativität von Architektur
  • Übergang von Architektur zu OOD: Umsetzung von Architekturen

Literatur:

  • Fowler, Martin: Software Architecture Guide, available online, accessed 2025-01-06
  • Fowler, Martin (2003). Who needs an architect? IEEE Software, 20(5), 11–13.
  • Buschmann, F., Meunier, R., Rohnert, H., Sommerlad, P. and Stal, M. (1996). Pattern-Oriented Software Architecture Volume 1: A System of Patterns, Wiley & Sons
  • Martin, Robert C. (2017). Clean Architecture: A Craftsman’s Guide to Software Structure and Design. Prentice Hall