Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Objektorientierung, Domain-Driven Design und Architectur

Objektorientierung, Domain-Driven Design und Architectur

My talk(German) I gave about DDD and software architecture.

Mirko Sertic

March 03, 2013
Tweet

More Decks by Mirko Sertic

Other Decks in Programming

Transcript

  1. Agenda Seite 2 • Ein paar Worte zu Projekten •

    Das Wesen von Software • Bausteine Domain-driven Design • Schichtenarchitektur mal anders • Messaging und WebServices • Weiterführende Themen • Diskussion
  2. Ein paar Worte zu Projekten Warum sind die Babylonier gescheitert?

    Seite 4 • Ein MONSTRÖSES Projekt • Sie wollten zu viel auf einmal • Sie haben sich mit höheren Mächten angelegt • Dafür wurden sie mit Sprachverwirrung bestraft • Die Projektbeteiligten haben sich nicht mehr verstanden • Zum Schluss gingen alle getrennte Wege • Übrig blieb eine Ruine
  3. Ein paar Worte zu Projekten Die Welt der Informatik Seite

    5 • Wir haben grosse Projekte • Wir haben ehrgeizige Ziele • Wir haben wenig Zeit • Manchmal auch Sprachverwirrung • Verstehen wir unsere Kunden wirklich? • Niemand will eine Ruine Und das alles gibt es gratis ohne biblischen Fluch ;-)
  4. Das Wesen von Software Fangen wir mit Software an Seite

    6 • Software ist immateriell • Sie besteht aus den Sprachen und Notationen, in denen sie formuliert ist • Software ist auch ein Modell • Ein Modell ist die Abbildung eines Realitätsausschnitts • Modell = Struktur + Verhalten • Das Modell definiert die Umsetzung der Anforderungen unserer Stakeholder
  5. Das Wesen von Software Mit Modellen ist das so eine

    Sache Seite 7 Der Informatiker(Wir) Der Kunde(Vertrieb) Welches Framework? Der Webshop muss gut Welche Programmiersprache? aussehen Es geht um einen Webshop… Der Kunde(Finanzbuchhaltung) Ich brauche eine Statistik über Quartalszahlen Modell
  6. Das Wesen von Software Warum brauchen wir ein Modell Seite

    8 • Wir brauchen einen Überblick • Wir brauchen eine Diskussionsgrundlage • Wir müssen Zusammenhänge verstehen • Wir brauchen einen (Bau)Plan unserer Software
  7. Das Wesen von Software Wie funktioniert Modellbildung? Seite 9 •

    Abgrenzung • Nichtberücksichtigung irrelevanter Objekte • Dekomposition • Zerlegung und Auflösung in einzelne Segmente(Teilmodelle) • Reduktion • Weglassen von Objektdetails • Aggregation • Vereinigung von Segmenten zu einem Ganzen • Abstraktion • Begriffs- bzw. Klassenbildung
  8. Das Wesen von Software Aber wir machen doch OO! Seite

    10 • Jein! • Object Oriented Programming vs. Object Based and Data Centric Programming(DCP) • DCP bricht schnell zusammen, weil • Prozedural programmiert wird und • die Möglichkeiten von OOP nicht ausgenutzt werden • «OOP isn’t about creating re-usable classes, it is about creating usable classes»
  9. Bausteine Domain-driven Design Kommen wir zu Domain-driven Design Seite 11

    Ist eine Methode, um Systeme zu modellieren verwandt mit Systems Engineering Ist kein PM-Vorgehensmodell wie z.B. HERMES oder V-Modell Hilft uns, Komplexität im Griff zu behalten
  10. Bausteine Domain-driven Design Kommen wir zu Domain-driven Design Seite 12

    • DDD ist eine Herangehensweise an die Modellierung komplexer (objektorientierter) Software • Der Begriff wurde von Eric Evans geprägt. Er nennt sich selbst einen «Domain Linguist» • Es ist mehr als eine Technik oder Methode, es ist eine Denkweise zur Steigerung der Produktivität im Umfeld komplexer fachlicher Zusammenhänge • Der Schwerpunkt des Modells liegt auf Fachlichkeit und Fachlogik • Das Modell spricht eine eigene, allgegenwärtige Sprache, welche von allen Projektbeteiligten verstanden wird
  11. Bausteine Domain-driven Design Domain-driven Design Seite 13 • ist eine

    evolvierende Struktur • Unser Modell ist nicht von Anfang an perfekt, es lebt und wird laufend verfeinert und erweitert • definiert ein System • und das Zusammenspiel von Teilsystemen mittels Schnittstellen und Ereignissen • bildet Fachwissen ab • durch Einsatz der allgegenwärtigen Sprache
  12. Bausteine Domain-driven Design Domain-driven Design Seite 14 • Unterstützt agile

    Vorgehensweisen • Iteratives Vorgehen und schrittweises Verfeinern des Modells ist klar gewünscht • Das Modell ist nicht nur ein Artefakt • es ist ein Kommunikationsmittel zwischen Stakeholdern, Lieferanten und Projektmitarbeitern • Software = Modell, Modell = Software • DDD geht mit jeder Programmiersprache, wird aber primär im OO Umfeld eingesetzt
  13. Bausteine Domain-driven Design Fangen wir mal an mit dem Webshop

    Seite 15 • Schritt eins: Bestandsaufnahme und Abgrenzung • UML Usecase Diagramm uc Use Case Model simplyfied Webshop Webshop «business actor» Finanzbuchhaltung «business actor» Vertrieb «business actor» Lagerist «business actor» Kunde Quartalsstatistik erzeugen Artikel pflegen Artikel versenden Artikel bestellen
  14. Bausteine Domain-driven Design Unser Modell wächst Seite 16 • Neue

    Anforderungen • Das wird schnell unübersichtlich uc Use Case Model extended Webshop Webshop «business actor» Finanzbuchhaltung «business actor» Kunde «business actor» Lagerist «business actor» Vertrieb Artikel bestellen Artikel pflegen Artikel versenden Quartalsstatistik erzeugen Jahresabschluss erstellen Liquiditätsstatistik erstellen Inventur durchführen Totes Kapital ermitteln Tops & Flops ermitteln Werbekampagnen starten Reklamationen machen Bewertungen abgeben
  15. Bausteine Domain-driven Design Was tun? Seite 17 • Schritt zwei:

    Dekomposition (Zerlegung) • DDD nennt das eine Context-Map class Context Map Geschäftsdomäne Finanzbuchhaltung (Unter-Domäne) Lagerverwaltung (Unter-Domäne) Webshop (Unter-Domäne) Vertrieb (Unter-Domäne) «business actor» Finanzbuchhaltung «business actor» Kunde «business actor» Lagerist «business actor» Vertrieb
  16. Bausteine Domain-driven Design Was bedeuten die neuen Begriffe Seite 18

    • Domain • Ist der sog. Problembereich(Problemspace). Hier wird das zu lösende Problem oder die zu lösende Aufgabe beschrieben • Bounded Context • Ist der sog. Lösungsbereich(Solutionspace). Ein Bounded Context beschreibt, wie eine Funktionalität in der Software umgesetzt wird. Ein Bounded Context ist in der Regel ein Subsystem oder eigenständiges Lieferobjekt. • Domain und Bounded Context sollten sich überlappen
  17. Bausteine Domain-driven Design Wir bauen einen Bounded Context Seite 19

    • Schritt 3: Reduktion und Abstraktion • UML Klassen und Verhaltensdiagramme class Lagerverwaltung Bounded Context Lagerverwaltung Bounded Context Lagerverwaltung Bounded Context «Domain Entity» Lagerbuchung - buchungId :int - artikelID :ArtikelID - abgangsMenge :int «Aggregate Root» Lieferung - lieferungId :int - kundenId :int «Value Object» Zustellinformationen - versandArt :VersandArt - anschrift :Anschrift «Aggregate Root» Lieferungsverfolgung - verfolgungsId :int - lieferungId :int - status :Verfolgungsstatus 1..* «knows»
  18. Bausteine Domain-driven Design Was bedeuten die neuen Begriffe Seite 20

    • Entity • Ein Ding aus der echten Welt, welches eine eindeutige ID hat. Ein Entity entspricht nicht einer Datenbanktabelle! • Value Object • Ist kein Ding, sondern ein Wert wie z.B. ein Geldbetrag oder auch eine Postanschrift. Ein Value Object hat keine eindeutige ID • Aggregate • Ein Aggregate sorgt dafür, dass eine Geschäftsregel eingehalten wird, z.B. kein Versand ohne Lagerbuchung
  19. Bausteine Domain-driven Design Konsequenzen für das Modell Seite 21 •

    Entities sind keine JavaBeans • Nicht jedes Attribut braucht eine Get- und Setmethode. Dies würde die Kapselung unterwandern • Value Object sind immutable • Sie können ihren Zustand nicht verändern und müssen immer komplett ersetzt werden. Sehr gut geeignet für Multi- Threaded Systeme. Stichwort «Functional Objects». • Aggregates kapseln Zugriff • Von aussen kann nur auf das Aggregate Root zugegriffen werden. Dadurch wird der Zugriff auf komplexe Objektgraphen gekapselt und Impl.-Details versteckt.
  20. Bausteine Domain-driven Design Das Aggregate, das unbekannte Wesen Seite 22

    • Aggregates sind Entities mit zusätzlichen Aufgaben • Aggregate = Objektgraph • Aggregate verweisen auf andere Aggregate via ID, und nicht via Objektreferenz • Faustformel: Ein Aggregate kapselt Zugriff auf max. 2-3 Entities • Sinnvoll angewendet führen sie zu weniger LazyInitializationExceptions • Keine Tuning der Hibernate Mappings mehr nötig, in der Regel wird Eager-Loading verwendet
  21. Bausteine Domain-driven Design Das sieht dann so aus… Seite 23

    class Lagerverwaltung Bounded Context Lagerverwaltung Bounded Context Lagerverwaltung Bounded Context «Domain Entity» Lagerbuchung - buchungId :int - artikelID :ArtikelID - abgangsMenge :int + getBuchungId() :int + getArtikelID() :ArtikelID + getAbgangsMenge() :int «Aggregate Root» Lieferung - lieferungId :int - kundenId :int - status :LieferungStatus + getLieferungId() :int + getKundenId() :int + getZustellinformationen() :Zustellinformationen + changeZustellinformationen(Zustellinformationen) :void + getLieferungStatus() :LieferungStatus «Value Object» Zustellinformationen - versandArt :VersandArt - anschrift :Anschrift + getVersandArt() :VersandArt + getAnschrift() :void «Aggregate Root» Lieferungsverfolgung - verfolgungsId :int - lieferungId :int - status :Verfolgungsstatus + getVerfolgungsId() :int + getLieferungsId() :int + getVerfolgungsstatus() :Verfolgungsstatus 1..* «knows»
  22. Bausteine Domain-driven Design Der Lebenszyklus von Objekten Seite 25 •

    Entities und Aggregates werden von Factories oder Buildern erzeugt. Ein direkter Aufruf von «new» ist verboten • Entities und Aggregates werden über Repositories persistiert • Entities und Aggregates können über Repositories rekonstituiert werden • Ein Repository ist kein DAO, da es Teil des Fachmodells und kein technisches Artefakt ist
  23. Bausteine Domain-driven Design Das sieht dann so aus… Seite 26

    class Domain Object Lifecycle «Aggregate Root» Lieferung - lieferungId :int - kundenId :int - status :LieferungStatus + getLieferungId() :int + getKundenId() :int + getZustellinformationen() :Zustellinformationen + changeZustellinformationen(Zustellinformationen) :void + getLieferungStatus() :LieferungStatus «Factory» LieferungFactory + createLieferung(int) :Lieferung LieferungBuilder + fuerKunde(int) :LieferungBuilder + build() :LieferungBuilder «interface» LieferungRepository + add(Lieferung) :void + get(int) :Lieferung + sucheMitKundenId(int) :Lieferung + sucheNachStatus(LieferungStatus) :Lieferung «creates» «creates» «persist,reconstitute»
  24. Bausteine Domain-driven Design Ein kompletter Anwendungsfall Seite 27 • Die

    Umwelt muss mit den Bounded Contexten interagieren • Der Bounded Context stellt dafür Schnittstellen zur Verfügung • Diese Schnittstellen heissen Domain Services • Ein Domain Service verhält sich wie eine Fassade, er kapselt Komplexität
  25. Bausteine Domain-driven Design Beispiel: Versand einer Lieferung Seite 28 class

    Beispiel Lieferung versenden «Domain Service» LieferungDomainService + createLieferung(LieferungSpecification) :LieferungId «Factory» LieferungFactory + createLieferung(KundenId) :Lieferung LagerbuchungFactory + createLagerbuchung(ArtikelID, int) :Lagerbuchung «Aggregate Root» Lieferung - lieferungId :LieferungId - kundenId :KundenId - status :LieferungStatus + getLieferungId() :LieferungId + getKundenId() :KundenId + getZustellinformationen() :Zustellinformationen + changeZustellinformationen(Zustellinformationen) :void + getLieferungStatus() :LieferungStatus + addLagerbuchung(LagerbuchunfFactory, ArtikelID, Int) :void «Domain Entity» Lagerbuchung - buchungId :int - artikelID :ArtikelID - abgangsMenge :int + getBuchungId() :int + getArtikelID() :ArtikelID + getAbgangsMenge() :int «interface» LieferungRepository + add(Lieferung) :void + get(LieferungId) :Lieferung + sucheMitKundenId(KundenId) :Lieferung + sucheNachStatus(LieferungStatus) :Lieferung «creates» 1..* «creates» «use» «persist,reconstitute»
  26. Bausteine Domain-driven Design Ein paar Worte zur Objektorientierung Seite 29

    • Ein Name ist ein Name und kein String • Immutable Objects bevorzugen • Soviel Logik wie möglich in Value Objects packen • Command-query separation einhalten(CQS Principle) • Lesender Code liefert ein Ergebnis und ist nicht destruktiv • Schreibender Code verändert einen Zustand, ist aber immer vom Typ void. Aussnahme : Domain Services • Eigenständige Methoden für lesenden und schreibenden Code • Single responsibility principle einhalten(SRP)
  27. Schichtenarchitektur mal anders Die klassische Schichtenarchitektur Seite 30 • Beispiel

    für strikte Schichtentrennung • Transitive Abhängigkeiten sind auch Abhängigkeiten • Geschäftslogik ist indirekt abhängig von der Infrastruktur • Stammt noch aus J2EE Zeiten(1999) cmp Klassische Schichten User Interface Layer + LieferungPresenter + LieferungView + LieferungViewModel Business Layer + LieferungService Data Access Layer + LieferungDAO + hibernate Infrastructure Layer + DataSource
  28. Schichtenarchitektur mal anders IoC mit hexagonale Architektur Seite 31 •

    So sieht es aus in der DDD-Welt • Entspannte Schichtenarchitektur, Einsatz von CDI • Entity != DTO • Domain Model ist technologieneutral class DDD Schichten Domain Layer + Lagerbuchung + LagerbuchungFactory + Lieferung + LieferungDomainService + LieferungFactory + LieferungRepository Application Layer + LieferungDTO + LieferungService + LieferungSpecification User Interface Layer + LieferungPresenter + LieferungView + LieferungViewModel + SessionManager Infrastructure Layer + HTTPSessionSessionManagerImpl + LieferungRepositoryHibernateImpl + LieferungRESTResource + LieferungSOAPWebService
  29. Messaging und WebServices Integration von Unter-Domänen Seite 32 • Abruf

    von Lagerbestand Webshop -> Lagerverwaltung • Bestellung versenden Webshop -> Lagerverwaltung class Context Map Geschäftsdomäne Finanzbuchhaltung (Unter-Domäne) Lagerverwaltung (Unter-Domäne) Webshop (Unter-Domäne) Vertrieb (Unter-Domäne) «business actor» Finanzbuchhaltung «business actor» Kunde «business actor» Lagerist «business actor» Vertrieb
  30. Messaging und WebServices Konzeptionelle Möglichkeiten Seite 33 • Synchrone Abfrage(blockierender

    Aufruf) • Nutzung von SOAP oder REST • REST bevorzugen, da durch Proxy-Server cachebar(Stichwort etag und expiry-time im HTTP Header)! • Asynchrone Abfrage(nicht blockierend) • Nutzung von JMS oder AMQP • Immer Double-Dispatch von Nachrichten, da Messaging System nicht verfügbar sein kann
  31. Messaging und WebServices Synchroner Aufruf(Beispiel) Seite 34 • REST oder

    SOAP? • Abfrage des Lagerbestandes ist häufig • Muss das immer neu berechnet werden? • Können wir das nicht cachen? • REST GET Request bevorzugen, z.B. http://mydomain/artikel/<Artikelnummer>/bestand.json • Kann von Proxy-Servern gecached werden, Stichwort Etag und Expiry-Time
  32. Messaging und WebServices Ansynchroner Aufruf mit DDD Seite 35 •

    DDD kennt das Konzept von sog. Domain Events • Ein Domain Event ist ein fachliches Ereignis, z.B. Kunde hat Bestellung aufgegeben • Domain Events werden von einem Bounded Context produziert und können von anderen Bounded Contexten konsumiert werden • Aber Achtung: Events müssen gecached werden, da z.B. auch die Messaging Middleware nicht verfügbar sein kann. Daher immer Double-Dispatch! • Events immer mit Zeitstempel und eindeutiger ID. So kann Reihenfolge und Verarbeitung protokolliert werden
  33. Messaging und WebServices Ansynchroner Aufruf(Beispiel) Seite 36 • Event wird

    von einem Aggregate erzeugt und in einem EventRepository persistiert • Im Infrastructure Layer gibt es einen Timer, welcher das EventRepository ausliest und bei Verfügbarkeit der Messaging Middleware(JMS / AMQP) weiterleitet • In konsumierenden Bounded Context gibt es im Infrastructure Layer einen MessageListener, welcher auf Nachrichten hört • Diese Nachrichten werden via ApplicationService an die Geschäftslogik übergeben. Deshalb muss Infrastructure Layer auch ganz oben und nicht ganz unten sitzen!
  34. Weiterführende Themen Weitere Begriffe der DDD-Welt Seite 37 • Open-host

    Service(OHS) • Ist eine Sammlung von Services, welche von einem Bounded Context zur Verfügung gestellt werden • Anti-corruption Layer(ACL) • Adapter von einem Bounded Context für den Zugriff auf den OHS eines anderen Bounded Context • Generic Subdomain • Beinhaltet gemeinsame Typen, wie z.B. KundenId oder ArtikelID, aber keine Geschäftslogik
  35. Weiterführende Themen Der JavaBean Mythos Seite 38 • Die JavaBean

    Spezifikation wurde ursprünglich für GUI Widgets erstellt • 0-Arg Konstruktor • Public Getter und Setter für Properties • Optionale BeanInfo Klassen • Niemand sagt, dass alles eine JavaBean sein muss! • Hibernate kann seit Version 2 auch Field-Access, keine Setter und Getter mehr notwendig, JPA kann das auch • Es reicht auch ein Package-Visibility 0-Arg Konstruktor
  36. Weiterführende Themen Weiterführende Themen Seite 39 • Viele statische Strukturen

    wie z.B. Interfaces und Domänenobjekte können aus dem Modell generiert werden • Für Enterprise Architect gibt es die MDG Erweiterungen • Dadurch bleibt Modell und Code synchron • Für dynamisches Verhalten ist UML eher ungeeignet • Die DDD Prinzipien können auf alle OO-Sprachen übertragen werden, DDD unterstützt auch funktionale Programmierung • Arc42 Framework für Dokumentationen
  37. Zusammenfassung Seite 40 Domain-driven Design führt zu stabilen und langfristig

    wartbaren Systemen DDD ist kompatibel zu Agilen Methoden DDD ist nicht schwer und macht Spass!