5 Punkte von GN⁺ 2025-03-29 | 1 Kommentare | Auf WhatsApp teilen
  • Komplexe Python-Anwendungen lassen sich mit zunehmender Größe mit einfachen Implementierungsansätzen allein nur schwer testen und ändern; dieses Buch behandelt als Lösung Architekturmuster anhand von Codebeispielen
  • Am Beispiel des Online-Möbelhandels von MADE.com und einer globalen Lieferkette steht Domain Modeling im Mittelpunkt, bei dem reale Betriebsprobleme in Softwaremodelle übertragen werden
  • Zentrale Achsen sind TDD, DDD und ereignisbasierte Architektur; Ziel sind schnelle Unit-Tests, wenige E2E-Tests, ein von Infrastruktur getrenntes Modell und nachrichtenbasierte Integration
  • Verwendet werden Flask, SQLAlchemy, pytest, Docker und Redis, der Fokus liegt jedoch darauf, eine Struktur zu schaffen, in der konkrete Technologieentscheidungen zu Implementierungsdetails werden
  • Wer Erfahrung mit komplexen Python-Anwendungen hat, kann das Buch lesen; Vorkenntnisse in DDD oder klassischen Mustern der Anwendungsarchitektur sind nicht erforderlich

Ausgangspunkt: eine Struktur, die leicht zu testen ist

  • Nach Harrys früherem Buch Test-Driven Development with Python blieb die Frage offen, wie Anwendungen strukturiert werden sollten, damit sie leicht testbar sind
  • Der Kern besteht darin, eine Struktur zu schaffen, in der Business-Logik ausreichend mit Unit-Tests abgedeckt wird und die Zahl der Integrations- und E2E-Tests möglichst gering bleibt
  • Begriffe wie „Hexagonal Architecture“, „Ports and Adapters“ und „Functional Core, Imperative Shell“ wurden erwähnt, doch damals waren sie in der Praxis noch nicht ausreichend verstanden oder umgesetzt
  • Bob wurde zum Architekten, weil es im Team niemanden gab, der Softwarearchitektur übernehmen konnte, und lernte von Ian Cooper neue Ansätze für das Schreiben von Code und das Denken darüber

MADE.com-Fallbeispiel: eine Lieferkette in Software modellieren

  • Die beiden Autoren arbeiteten beim europäischen E-Commerce-Unternehmen MADE.com und wandten die Techniken des Buchs auf den Aufbau eines verteilten Systems zur Modellierung realer Geschäftsprobleme an
  • Die Beispieldomäne basiert auf dem ersten System, das Bob bei MADE entwickelte, und verfolgt das Ziel, Inhalte festzuhalten, die neuen Programmierern beim Einstieg ins Team vermittelt werden mussten
  • MADE.com betreibt eine globale Lieferkette aus Frachtpartnern und Herstellern
    • Um Kosten zu senken, sollen Lieferungen so optimiert werden, dass Waren nicht lange im Lager liegen
    • Idealerweise kommt ein Sofa genau an dem Tag im Hafen an, an dem der Kunde es kauft, und wird ohne Zwischenlagerung direkt nach Hause geliefert
    • Da Waren per Containerschiff bis zu drei Monate unterwegs sein können, ist die zeitliche Abstimmung schwierig
  • Im realen Betrieb treten ständig Variablen auf, etwa Beschädigungen, Wasserschäden, Verzögerungen durch Stürme, Bearbeitungsfehler von Logistikpartnern, fehlende Dokumente oder Bestelländerungen durch Kunden
  • Um solche Probleme zu bewältigen, sollen reale betriebliche Abläufe in Software abgebildet und möglichst viele Aufgaben automatisiert werden

Grenzen, die sichtbar werden, wenn Python-Projekte wachsen

  • Python ist schnell gewachsen und gereift, wird aber nun zunehmend mit Problemen betraut, mit denen sich die C#- und Java-Welten schon lange beschäftigen
  • Startups werden zu echten Unternehmen, und Web-Apps sowie Skript-Automatisierung wachsen zu Enterprise-Software heran
  • Zur Python-Philosophie gehört „There should be one—and preferably only one—obvious way to do it“, doch wenn Projekte größer werden, ist der offensichtlichste Weg nicht immer geeignet, um Komplexität und sich ändernde Anforderungen zu beherrschen
  • Die im Buch behandelten Techniken und Muster sind nicht neu, gelten aber größtenteils als vergleichsweise neu in der Python-Welt
  • Das Buch will Eric Evans’ Domain-Driven Design oder Martin Fowlers Patterns of Enterprise Application Architecture nicht ersetzen; es verweist häufig auf diese Klassiker und empfiehlt ihre Lektüre
  • Codebeispiele in der vorhandenen Literatur sind oft in Java oder C++/# geschrieben, was für Python-Entwickler eine Hürde beim Lesen sein kann

Drei Werkzeuge zum Umgang mit Komplexität

  • Test-Driven Development (TDD) hilft dabei, korrekten Code zu schreiben und ohne Angst vor Regressionen zu refaktorieren oder Funktionen hinzuzufügen
    • Behandelt wird, wie Tests möglichst schnell ausgeführt werden
    • Wie man aus schnellen, abhängigkeitfreien Unit-Tests möglichst viel Abdeckung und Feedback gewinnt
    • Und wie man langsame und instabile E2E-Tests minimiert
  • Domain-Driven Design (DDD) hilft, sich auf ein gutes Modell der Geschäftsdomäne zu konzentrieren
    • Behandelt wird, wie verhindert wird, dass das Modell an Infrastrukturbelange gekoppelt wird
    • Und wie verhindert wird, dass das Modell schwer änderbar wird
  • Lose gekoppelte Microservices, die über Nachrichten integriert werden und manchmal als reactive microservices bezeichnet werden, werden als Lösung zur Beherrschung von Komplexität zwischen mehreren Anwendungen oder Geschäftsdomänen behandelt
    • Wie sie mit bestehenden Werkzeugen des Python-Ökosystems wie Flask, Django und Celery zusammenspielen, ist nicht immer offensichtlich
  • Auch wer keine Microservices verwendet oder kein Interesse daran hat, kann die meisten Muster des Buchs und einen großen Teil der Inhalte zur ereignisbasierten Architektur auch auf eine monolithische Architektur anwenden

Leser und vorausgesetztes Wissen

  • Das Buch setzt Leser voraus, die schon aus der Nähe mit einigermaßen komplexen Python-Anwendungen gearbeitet haben
  • Es richtet sich an Leser, die die Schmerzen des Umgangs mit Komplexität erlebt haben
  • Vorwissen zu DDD oder klassischen Mustern der Anwendungsarchitektur ist nicht erforderlich
  • Die Erklärungen bauen kapitelweise rund um eine Beispielanwendung aufeinander auf
  • Da die Autoren bei ihrer Arbeit TDD verwenden, zeigen sie häufig zuerst den Testcode und danach die Implementierung
  • Flask, SQLAlchemy, pytest, Docker und Redis werden verwendet, aber Vertrautheit damit ist nur hilfreich, nicht zwingend erforderlich
  • Eines der Hauptziele ist es, eine Architektur zu schaffen, in der konkrete Technologieentscheidungen zu unwichtigen Implementierungsdetails werden

Aufbau des Buchs

  • Das Buch ist in zwei Teile gegliedert
  • Teil 1: Architektur zur Unterstützung des Domain Modeling

    • Domain Modeling und DDD werden in Kapitel 1, 2 und 7 behandelt
    • Ausgangspunkt ist die Annahme, dass komplexe Geschäftsprobleme als Domain Model im Code abgebildet werden müssen
    • Erklärt wird, wie man mit einem Modell beginnt, das keine externen Abhängigkeiten hat und schnelle Unit-Tests ermöglicht
    • Später werden die Wahl geeigneter Aggregates und Fragen der Datenintegrität erneut behandelt
    • Die Muster Repository, Service Layer und Unit of Work werden in Kapitel 2, 4 und 5 behandelt
    • Diese Muster ergänzen einander, um das Modell von unnötigen Abhängigkeiten zu trennen
    • Rund um den persistenten Speicher wird eine Abstraktionsschicht geschaffen, dazu eine Service-Schicht, die die Einstiegspunkte des Systems und die wichtigsten Use Cases erfasst
    • Gezeigt wird eine Struktur, mit der sich schlanke Einstiegspunkte wie eine Flask-API oder eine CLI leicht erstellen lassen
    • Die Diskussion über Abstraktion und Tests wird in Kapitel 3 und 5 fortgesetzt
    • Nach der Einführung des Repository-Patterns geht es darum, wie man Abstraktionen auswählt und welche Rolle Abstraktion bei Kopplungsformen spielt
    • Nach dem Service-Layer-Pattern werden die Testpyramide und die Frage behandelt, wie Unit-Tests auf möglichst hoher Abstraktionsebene geschrieben werden können
  • Teil 2: Ereignisbasierte Architektur

    • Ereignisbasierte Architektur wird in Kapitel 8 bis 11 behandelt
    • Vorgestellt werden die Muster Domain Events, Message Bus und Handler
    • Domain Events dienen dazu, auszudrücken, dass eine bestimmte Interaktion im System eine andere Aktion auslöst
    • Der Message Bus sorgt dafür, dass Aktionen Events auslösen und die passenden Handler aufgerufen werden
    • Behandelt wird, wie Events in einer Microservices-Architektur als Integrationsmuster zwischen Services genutzt werden
    • Es wird zwischen Commands und Events unterschieden; die Anwendung wird im Kern zu einem System zur Nachrichtenverarbeitung
    • Kapitel 12 behandelt CQRS-Beispiele sowohl mit als auch ohne Events
    • Kapitel 13 räumt explizite und implizite Abhängigkeiten auf und implementiert ein einfaches Framework für Dependency Injection
    • Der Epilog zeigt, wie sich diese Prinzipien nicht nur auf ein neu begonnenes einfaches Beispiel, sondern auf bestehende Software anwenden lassen, und bietet weiterführende Lektüre

Beispielcode und Mitmachen

  • Das Buch ist um ein einzelnes Beispielprojekt herum aufgebaut, das im Verlauf der Kapitel schrittweise erweitert wird
  • Wichtig ist, dass Leser den Code tatsächlich selbst anfassen und ein Gefühl dafür bekommen, wie die Muster funktionieren
  • Der gesamte Code liegt auf GitHub, und für jedes Kapitel gibt es einen eigenen Branch
  • Drei Vorgehensweisen werden vorgeschlagen
    • Ein eigenes Repository erstellen, die Beispiele aus dem Buch nachbauen und bei Bedarf das Repository der Autoren als Referenz nutzen
    • Die einzelnen Muster kapitelweise in einem eigenen kleinen Projekt ausprobieren
    • Die „Exercise for the Reader“ jedes Kapitels und den teilweise lückenhaften GitHub-Code nutzen, um schnell praktisch zu üben
  • Gerade für Leser, die die Muster auf eigene Projekte anwenden wollen, ist es eine sichere Übung, zuerst mit einem einfachen Beispiel zu arbeiten
  • Mindestens wird empfohlen, beim Lesen jedes Kapitels den Code per git checkout aus dem Repository zu holen und ihn im Kontext einer tatsächlich laufenden Anwendung anzusehen

Lizenz und Format

  • Der Code und die Online-Version stehen unter der Lizenz Creative Commons CC BY-NC-ND
    • Nichtkommerzielle Zwecke
    • Namensnennung
    • Kopieren und Teilen erlaubt
  • Die Druckausgabe unterliegt einer eigenen Lizenz; bei Bedenken zur Wiederverwendung wird auf O’Reilly verwiesen
  • Die typografischen Konventionen des Buchs unterscheiden zwischen kursiv, Festbreite, fetter Festbreite und kursiver Festbreite
    • Kursiv kennzeichnet neue Begriffe, URLs, E-Mail-Adressen, Dateinamen und Erweiterungen
    • Festbreite kennzeichnet Programmlistings und Codeelemente
    • Fette Festbreite kennzeichnet Befehle oder Text, die der Benutzer genau so eingeben soll
    • Kursive Festbreite kennzeichnet Text, der durch vom Benutzer bereitgestellte oder kontextabhängig bestimmte Werte ersetzt wird

1 Kommentare

 
xguru 2025-03-29

Es gibt eine koreanische Ausgabe: Architekturpattern mit Python