Auf einen Blick

  • Die Applikationsschicht (Applikationshexagon) steuert Anwendungsfälle: sie ruft Domänenlogik auf, orchestriert Infrastruktur-Zugriffe und koordiniert mit anderen Komponenten/Anwendungen. Zentrale Objekte sind Inbound Ports (Klassen, implementieren Use-Case-Interfaces).
  • Fachliche Aufgaben: Ablaufsteuerung von Anwendungsfaellen und DTO-Mapping (Konvertierung Domaenenobjekt <-> DTO). Querschnittliche Aufgaben: Transaktionssteuerung, Sperren, Validierung, Berechtigungspruefung, Ausnahmebehandlung, Logging, Protokollierung.
  • Datenaustausch nach aussen erfolgt ueber DTOs (Data Transfer Objects) – reine Datenobjekte ohne Logik, nicht garantiert validiert, aenderbar. Entitaeten verlassen die Komponente nicht (Ausnahme: Sonderstellung der Datenbank, deren Daten bereits validiert sind).
  • Querschnittsthemen mit klausurrelevanten Details: Isolation Levels (Read Uncommitted bis Serializable) und die drei Inkonsistenzen (Dirty/Non-Repeatable/Phantom Reads), Propagation, Read-Only; optimistisches vs. pessimistisches Sperren.
  • Sicherheit und Betrieb: Berechtigungen ueber Rollen und Gruppen, Zero Trust (Client) vs. Full Trust (Domaene), zwei Verteidigungslinien; Log-Ebenen FATAL/ERROR/WARN/INFO/DEBUG/TRACE, MDC, Korrelations-ID; Protokollierung via Audit-Felder oder Geschaeftstransaktionen.
  • Durchgaengiges Beispiel: Adresse eines Mitarbeiters (Employee) im Self-Service aendern – 10-Schritt-Ablauf durch Infrastruktur, Applikation und Domaene.

Kernkonzepte

1. Referenzarchitektur der logischen Sicht (hexagonales Modell)

Eine Unternehmensanwendung besteht aus Komponenten (z.B. rootpackage.a, rootpackage.b), die jeweils in drei Hexagon-Schichten aufgeteilt sind: Infrastructure (*.infra) mit Inbound- und Outbound-Adaptern, Application (*.application) mit Inbound- und Outbound-Ports, und Domain (*.domain) mit Wurzelentitaet, Aggregat (ID), Entitaet (ID), Wertobjekt, Domain Service und Domain Event. Wichtig ist die Codeabhaengigkeit: Abhaengigkeiten zeigen von aussen nach innen zur Domaene (DIP).

2. Aufgaben der Applikationsschicht – fachlich vs. querschnittlich

Fachliche Aufgaben: Ablaufsteuerung von Anwendungsfaellen (Aufruf der Domaenenlogik, Koordination mit anderen Komponenten, Orchestrierung der Infrastruktur-Zugriffe, Koordination mit anderen Anwendungen) sowie DTO-Mapping (Konvertierung zwischen Domaenenobjekten und DTOs). Querschnittliche Aufgaben: Transaktionssteuerung, Sperrmechanismus, Validierung, Berechtigungspruefung, Ausnahmebehandlung (nicht ausschliesslich hier), Logging (nicht ausschliesslich hier) und Protokollierung.

3. Ablaufsteuerung – durchgaengiges Beispiel Adresse aendern

Beispiel Adresse eines Mitarbeiters im Self-Service aendern, 10 Schritte: 1. HTTP-Request entgegennehmen (SelfServiceHttpInboundAdapter), 2. Transaktion starten und Sperre pruefen, 3. angemeldeten User abfragen (andere Komponente, AuthorizationOutboundPort), 4. Mitarbeiter von DB anfordern (EmployeeRepositoryOutboundPort), 5. Mitarbeiter aus DB lesen (EmployeeJPAOutboundAdapter), 6. Adresse aendern (RootEntity Employee, Domaenenlogik), 7. Mitarbeiter speichern anfordern, 8. Mitarbeiter in DB speichern, 9. Transaktion beenden, Sperre weg, Rueckgabeobjekt erstellen, 10. HTTP-Response erzeugen. Ein- und Ausgabe der InboundPort-Methode sind DTOs, keine Domaenenobjekte.

4. Datenobjekte und ihre Lage in den Schichten

Nach aussen (User Interface, externe Systeme) laufen Daten als JSON/XML in definiertem Format. Der HttpInboundAdapter (Infrastruktur) arbeitet mit DTOs; der InboundPort (Applikation) uebersetzt DTO in Domain Objects (Value Object oder Entity); die Domaene arbeitet mit (Root) Entity / Domain Service. Zwischen Komponenten koennen Werteobjekte oder DTOs ausgetauscht werden, aber keine Entitaeten (diese werden nicht exponiert). Sonderstellung der Persistenz: Die Datenbank ist der einzige Ort, gegenueber dem Entitaeten exponiert werden duerfen, weil die Daten in ihr bereits validiert sind – daher gibt der JPA-Adapter beim Lesen eine Entitaet (statt DTO) zurueck.

5. Entwurfsmuster Data Transfer Object (DTO)

Definition: Ein DTO fasst in einer verteilten Umgebung zu uebertragende Daten in einem eigenen Objekt zusammen, um die Anzahl der Aufrufe ueber das Netzwerk zu reduzieren. Abgrenzung zum Value Object: DTOs haben nur den Zweck Daten zu transferieren, enthalten keine Logik, sind aenderbar und garantieren nicht, dass ihre Daten validiert sind. Nichtfunktionaler Zweck: Netzwerklast reduzieren durch Buendelung; ISP – jedem Client seine eigenen DTOs. Funktionale Zwecke: Kombination (Daten aus mehreren Domaenenobjekten), Auslassen (nicht zu exponierende Daten weglassen), Anreicherung (Steuerungsinformationen, Metadaten zu Feldern), Konvertierung in andere Formate (flache Strukturen fuer XML/JSON) und Validierung (Objekte, die Daten aufnehmen ohne Invarianten zu erheben).

6. DTO-Implementierung als Java Bean und Layer Supertype

Im Java-Stack werden DTOs nach der Java-Bean-Spezifikation gebaut: Default-Konstruktor (und weitere nach Bedarf), private Felder, oeffentliche Getter und ggf. Setter mit Namenskonvention get[Fieldname]/set[Fieldname]. Das erlaubt generische Verarbeitung: Konvertierung in/von XML oder JSON und Validierung. Beispiel Employee.json enthaelt firstName, lastName, birthDate, salary. Ein Layer Supertype dient als Basisklasse; der Default-Konstruktor erlaubt standardisierte Erzeugung per Reflection. Felder sind Standardtypen, andere DTOs, ggf. Werteobjekte; das DTO kann Methoden zur Konvertierung von/in Domain Objects bieten.

7. Warum Transaktionssteuerung in der Applikationsschicht?

Die Datenbank fuehrt zwar jedes Statement in einer Transaktion aus (ACID) und macht danach Auto-Commit, aber sie weiss nicht: welche weiteren Statements zur selben Logical Unit of Work (demselben Use Case) gehoeren, wo die Grenzen eines Aggregates sind und wieviel Inkonsistenzen fuer bessere Skalierbarkeit akzeptabel sind. Transaktionssteuerung ist fachlich getrieben – die Ablaufsteuerung ist ihre richtige Heimat. Grundoperationen: Definieren, Starten, eigentliche Arbeit, Commit oder Rollback je nach Status. Beispiel Spring: PlatformTransactionManager steuert Transaktionen, TransactionDefinition definiert die Eigenschaften; in der Praxis nimmt man Template oder Annotationen gegen Boilerplate.

8. Transaktionseigenschaft Read-Only

Zeigt an, dass die Transaktion keine schreibenden Datenbankzugriffe macht – das kann die DB selbst nicht wissen, weil sie nicht kennt, was noch kommt. Funktion: verhindert Sperren von Tabelleneintraegen; ggf. Optimierungen im Persistenz-Framework (Entfall von Pruefungen auf geaenderte Daten). Beispiel: Wird eine haeufig benoetigte Werteliste read-only gelesen, muss eine zweite lesende Transaktion nicht warten. Praxis: bei lesenden Zugriffen immer den read-only Hinweis verwenden.

9. Transaktionseigenschaft Isolation und Inkonsistenzen

Volle Konsistenz heisst vollstaendige Isolation der Transaktionen – impliziert gegenseitiges Blockieren und damit schlechtere Skalierbarkeit. Drei Arten von Inkonsistenzen: Phantom Reads (T1 liest, T2 fuegt Zeilen ein und committed, T1 liest erneut und bekommt eine Zeile mehr), Non-Repeatable Reads (T1 liest, T2 aendert und committed, T1 liest erneut mit anderem Ergebnis) und Dirty Reads (noch nicht committete Aenderungen koennen gelesen werden). Isolation-Level-Tabelle: Read Uncommitted erlaubt alle drei; Read Committed verhindert Dirty Reads; Repeatable Read verhindert Dirty und Non-Repeatable Reads; Serializable verhindert alle drei.

10. Transaktionseigenschaft Propagation

Propagation regelt das Verhalten beim Aufruf einer transaktionalen Methode innerhalb einer bestehenden Transaktion (Beispiel: Use Case A Mitarbeiter laden wird von Use Case B Praemie auszahlen verwendet). Problem: Startet A eine eigene Transaktion und beendet sie, ist keine Wiederverwendung durch B moeglich. Erwuenschtes Verhalten fuer A: am Anfang neue Transaktion nur erzeugen, wenn keine existiert, sonst weiterverwenden; am Ende nur committen, wenn eine neue Transaktion erzeugt wurde. Moegliche Propagationsverhalten: vorhandene weiterfuehren sonst neue beginnen; vorhandene weiterfuehren sonst Fehler; vorhandene weiterfuehren sonst ohne Transaktion weiter; neue beginnen und existierende abbrechen (aussetzen); verschachtelte (nested) Transaktion beginnen.

11. Sperren – Notwendigkeit und Grundprinzip

Ein Sperrmechanismus ist Grundvoraussetzung fuer Mehrbenutzerfaehigkeit; Datenbanktransaktionen allein reichen fuer Datenkonsistenz nicht aus. Lost-Update-Problem: A und B lesen Datensatz 42, A aendert und speichert, dann aendert und speichert B – B ueberschreibt die Aenderungen von A (auch bei anderen Feldern). Es gibt zwei Arten: pessimistisch und optimistisch. Der Sperrmechanismus gilt auch fuer Hintergrundverarbeitung (Sperren setzen/loeschen, Wiederholung bei gesperrten Objekten).

12. Pessimistisches vs. optimistisches Sperren

Pessimistisch: Regel genau ein Anwender kann ein Datenobjekt aendern. Ablauf: Anwendung prueft, ob Sperre gesetzt ist; wenn nicht, wird Sperre fuer die (Web-)Session und das Aggregat in der DB gesetzt; nach dem Speichern wird sie entfernt; Timeout begrenzt die Sperrdauer. Vorteil: garantiertes Aendern fuer genau einen Akteur. Nachteil: Wechsel in Editiermodus noetig, gesperrte Objekte behindern andere. Optimistisch: Regel alle koennen aendern, wer zuerst schreibt gewinnt. Aggregat hat einen (nicht an den Client sichtbar gelieferten) Versionszaehler; beim Speichern wird die Client-Version mit der DB-Version verglichen; bei Ungleichheit kein Speichern; bei Erfolg wird der Zaehler um eins erhoeht. Vorteile: kein Editiermodus, keine gegenseitige Blockade, einfach (keine Sperrtabelle/kein Timeout), von Persistenz-Frameworks oft mitgeliefert. Nachteil: Datenverlust des Zweitschreibenden (Optimistic locking loser exception).

13. Validierung – Warum und die zwei Arten

Warum validieren: aussagekraeftige Fehlermeldungen (500 Server Error ist nicht hilfreich), Datenfehler verhindern (invalide Daten koennen wochenlang liegen und dann zuschlagen), Programmierfehler frueh erkennen (naeher an der Ursache) und als Sicherheitsnetz. Zwei Arten: Eingabevalidierung prueft, ob Input in die Anwendung korrekt ist – alle Validierungen vollstaendig, Fehler gesammelt und zusammen berichtet, Fehlermeldungen als Codes (I18N), Fehler sind Teil der vorgesehenen Funktionalitaet, HTTP 4** Return Code. Invariantenvalidierung prueft an diversen Stellen innerhalb der Anwendung – Einzelpruefung, kein Sammeln, Fehlertexte im Code, Invariantenfehler sind immer Programmierfehler, HTTP 5** Return Code.

14. Eingabevalidierung – wo und wie (Never trust the client)

Formatvalidierung im UI (Datumsformat, Pflichtfelder, erlaubte Zeichen) dient nur dem Bedienkomfort. Der Adapter validiert nicht (ausser Datentyp) – er uebersetzt nur zwischen Protokoll und Programmiersprache. Die vollstaendige Validierung gehoert in die Applikationsschicht am InboundPort (Never trust the client): Format- und fachliche Validierung; hier liegen DTOs mit noch nicht validierten Daten vor, DB-Zugriff via Outbound Port und Domaenenlogik (Validierungsregeln) sind erreichbar, Transaktion ist vorhanden. Prinzipien: nie dem Client vertrauen, aktiv validieren (fail early, nicht auf Ausnahmen warten), am Anfang vor der Geschaeftslogik validieren, alle Validierungen ausfuehren und Ergebnisse sammeln, Fehlermeldungen als Codes/Schluessel getrennt vom Text (I18N). Position im Ablauf: Transaktion beginnen, validieren (ggf. mit DB-Zugriff), DTO in Werteobjekte konvertieren, Domaenenlogik ausfuehren. Java Bean Validation deklariert Constraints am DTO, Fehlertexte im ResourceBundle (ValidationMessages_en.properties).

15. Warum DTO statt Werteobjekt zur Validierung; Invariantenvalidierung

Bei Dateneingabe muessen Daten erst validiert werden; dazu braucht man Objekte, die keine Invarianten garantieren – Werteobjekte wuerden bei invaliden Daten sofort eine Ausnahme werfen, daher DTOs. Eine Konvertierung in Werteobjekte bereits im Adapter verstiesse nicht gegen DDD-Regeln (Entitaeten verlassen die Komponente nicht, Infrastruktur darf von Domaene abhaengen), waere aber wegen der Validierung ungeeignet. Invariantenvalidierung findet an mehreren Stellen statt: Format-/Datentyp-Fehler beim Uebersetzen im Adapter, Pruefung gegen das Datenbankschema im RDBMS, Domaenenobjekte garantieren ihre Invarianten, und ggf. Pruefung der Ausgaben auf Plausibilitaet (Sicherheitsnetz).

16. Aufbau des Applikationshexagons und Ports

Beispiel Employee: Inbound Ports sind Klassen und implementieren Use-Case-Interfaces (PayrollEmployeeUseCases, HREmployeeUseCases, SelfServiceEmployeeUseCases) – nach ISP bekommt jeder Client sein eigenes Interface und seine Daten (DTOs). Der EmployeeInboundPort nutzt die Domaene (Employee, EmployeeDomainService). Outbound Ports sind Interfaces oder Klassen – je nach erlaubten Abhaengigkeiten von Hexagonen und Komponenten (DIP): EmployeeRepositoryOutboundPort, ControllingOutboundPort (Event Subscriber, der ein Employee-Event nimmt und an eine Message Queue Richtung ERP weiterleitet), AuthorizationOutboundPort (ruft einen Inbound Port in der Komponente Berechtigungen auf). Paketstruktur: API (hr/selfservice/payroll je mit Use Cases und DTO, shared DTO), Ports (inbound: Employee; outbound: Employee Repository, Reason Code Repository, Authorization, Controlling).

17. Berechtigungen – User, Rolle, Gruppe, Berechtigung

Berechtigungen pruefen, ob ein Nutzer das Recht hat etwas zu tun. Nutzer koennen (authentifizierte) Anwender, (authentifizierte) externe Anwendungen oder anwendungsinterne technische Nutzer (Hintergrundverarbeitung) sein. Berechtigung heisst: Code ausfuehren (im hexagonalen Modell einen Use Case = eine Methode; Beispiel NGHR: Manager duerfen Gehaltsdaten einsehen) oder auf Daten zugreifen (fuer einen bestimmten Datensatz; Beispiel: Manager nur Gehaltsdaten direkt unterstellter Mitarbeiter). Problem: sehr viele Berechtigungen (>= Anzahl Use Cases), pro User zu pflegen. Loesung Rollen: buendeln fachlich zusammengehoerige Berechtigungen (User ist Rolle zugeordnet, Rolle hat Berechtigung); Rollen(namen) befinden sich im Code. Gruppen entkoppeln weiter: Rollen feingranular, Gruppen entsprechen Taetigkeitsprofilen und werden im Unternehmensverzeichnis anwendungsuebergreifend gepflegt; bei Anmeldung werden Gruppen genannt und anwendungsspezifische Rollen zugeordnet (User ist Mitglied Gruppe, Gruppe ist zugeordnet Rolle, Rolle hat Berechtigung).

18. Wo Berechtigungen pruefen – Zero Trust vs. Full Trust

Moeglichst frueh pruefen (IT-Sicherheitsprinzip: Angriffsflaeche minimieren, Zero Trust). Im UI keine Berechtigungspruefung – Auswertung von Rollen dient nur der UI-Steuerung. Erste Verteidigungslinie im Web Server / HttpInboundAdapter: grobgranular auf HTTP-Methode (GET, POST, PUT, DELETE) und URL (z.B. /api/hr/payroll/**). Zweite Verteidigungslinie am Inbound Port: feingranular Berechtigung fuer Methode (Use Case) und fuer Daten. Die Domaene ist Full Trust und prueft nichts – sie nimmt an, immer mit geprueften Berechtigungen aufgerufen zu werden. Praxis: Konzept einfach halten (Aufwand, Betreibbarkeit); Personas identifizieren, Matrizen erstellen (Personas gegen Use Cases, ggf. Statusuebergaenge und Feld-Aenderungseinschraenkungen je Status, datenabhaengige Einschraenkungen); Berechtigungen auch fuer technischen Betrieb/Support und Power User nicht vergessen.

19. Ausnahmebehandlung – Modelle und Uebersetzung

Beispiel-Fehler: Der ERPOutboundAdapter wirft eine technologiespezifische javax.xml.transform.TransformerException, die im ERPOutboundPort (Applikation) gefangen wird – das ist eine unzulaessige Abhaengigkeit der Applikationsschicht von technologiespezifischem Code (JAXP), weil die Kapselung durch den Adapter eine Luecke hat (die geworfenen Ausnahmen). Loesung ueber Ausnahmemodelle: Outbound-Adapter uebersetzen technologiespezifische Ausnahmen in das Ausnahmemodell der Anwendung; Inbound-Adapter uebersetzen alle Ausnahmen in technologiespezifische Fehler (HTTP 400er/500er). Die Applikation definiert das Ausnahmemodell und stellt es der Infrastruktur zur Verfuegung, kennt aber keine technologiespezifischen Ausnahmen. Die Domaene kann ein domaenenspezifisches Modell definieren und werfen.

20. Ausnahmebehandlung – Regeln je Schicht

Standardausnahmen der Programmiersprache duerfen ueberall geworfen werden und muessen nicht uebersetzt werden. Infrastruktur: Inbound-Adapter mit zentraler Ausnahmebehandlung uebersetzt alle Ausnahmen fuer den Client; Outbound-Adapter uebersetzen alle technologiespezifischen Ausnahmen in das Ausnahmemodell der Anwendung (gilt fuer Request/Reply, bei nachrichtenbasierter Kommunikation anders). Applikation: wirft typischerweise Ausnahmen fuer Validierung, Berechtigungen und Sperren; definiert ein Ausnahmemodell (Standardausnahmen koennen externe Ressourcen-Ausnahmen wie DataAccessException nicht abbilden); Muss: fehleratomares Verhalten (z.B. Transaktion zurueckrollen); Optional: retry/fall-back/skip/notify. Domaene: Standardausnahmen (NPE, IllegalArgumentException, IllegalStateException) koennen reichen, eigenes Modell mit Basisklasse DomainException kann sinnvoll sein, um keine reine RuntimeException zu werfen.

21. Logging – Ebenen und Regeln

Log-Ebenen: FATAL (Fehler, der das Weiterfunktionieren der gesamten Anwendung unmoeglich macht), ERROR (Fehler, der die Weiterverarbeitung eines Vorgangs unmoeglich macht – kein Validierungsfehler), WARN (ungewoehnliche Situation, die kuenftig zu Problemen fuehren kann), INFO (relevantes fachliches Ereignis, z.B. Entitaet angelegt, Statusuebergang) – Zielpublikum Betrieb; DEBUG (Detail zum Nachvollziehen des Programmablaufs) und TRACE (noch detaillierter) steuern die Granularitaet – Zielpublikum Entwicklung. Weitere Regeln: Klarheit ueber den Zweck (einen Fehler loggen dient dem Beheben der Ursache), Werte als Information mitgeben, Kontext ueber Mapped Diagnostic Context (MDC – Key-Value-Paare pro Thread, am Ende MDC.clear()), strukturierte Logdaten (JSON/XML) und einheitliches Format, container-/cloud-tauglich (nicht ins Dateisystem, sondern in die Standardausgabe loggen), Sicherheit (keine sensitiven Informationen loggen), Logging ist kein Monitoring (Monitoring nutzt Metriken).

22. Logging in verteilten Systemen

In verteilten Systemen bringt verstreutes Logging auf vielen Servern nichts. Loginformationen als Datenstrom betrachten, zentral einsammeln (Log-Sammler), speichern (Log-Speicher) und mit Tools auswerten (Log-Auswerter). Eine Korrelations-ID (eindeutige ID pro urspruenglichem Request im verteilten System) ordnet zusammengehoerige Logeintraege zu; eine Span-ID pro Thread rekonstruiert die Reihenfolge unabhaengig von Zeitstempeln; ein parent-Feld verweist auf den uebergeordneten Span. Korrelations-ID und Span-ID werden als HTTP-Request-Header weitergegeben.

23. Protokollierung – Audit und Geschaeftstransaktionen

Ansatz 1 – Aenderungen mitschreiben: minimale Audit-Informationen in der Entitaet (created by/created at, changed by/changed at) sollten in keiner Anwendung fehlen. Vollstaendige Historie ueber Aenderungstabellen (Aenderungsereignis: wer wann welchen Typ mit welchem Identifizierer; Aenderungsdetails: alter/neuer Wert je Feld) – Befuellung programmatisch (Vergleich DB-Aggregat mit geaendertem Aggregat) oder per Datenbanktrigger; alternativ Datenbank versionieren (zweite Tabelle mit Versionsspalte, z.B. Hibernate Envers). Ansatz 2 – Aenderung als eigenes Objekt: Die Anwendung weiss ohnehin, was geaendert wird; statt Vorher/Nachher-Vergleich haelt sie die Aenderung als eigenes Objekt fest. Diese Geschaeftstransaktionen (Business Transactions) haben nichts mit Datenbanktransaktionen zu tun; sie enthalten alle Informationen zum Abarbeiten des Auftrags und werden doppelt genutzt (Abarbeiten und Speichern zur Protokollierung). Beispiel: ChangeEmployeeAddressTransaction mit Transaktionsnummer, Zeitstempel, User, Personalnummer, neue Adresse.

Merksätze

Definition DTO
Ein DTO fasst in einer verteilten Umgebung zu uebertragende Daten in einem eigenen Objekt zusammen, um die Anzahl der Aufrufe ueber das Netzwerk zu reduzieren. DTOs haben nur den Zweck Daten zu transferieren, enthalten keine Logik, sind aenderbar und garantieren nicht, dass ihre Daten validiert sind.
Inbound Ports sind die zentralen Objekte
Inbound Ports implementieren Use-Case-Interfaces (ISP), nehmen Eingaben von Inbound Adaptern entgegen, nutzen Outbound Ports fuer Zugriff auf externe Systeme, andere Komponenten und Datenbank, uebersetzen zwischen Domaenenmodell und DTOs und kuemmern sich um Sperren, Transaktionssteuerung, Berechtigungspruefung, Protokollierung/Logging, Ausnahmebehandlung und Validierung.
Transaktionssteuerung ist fachlich getrieben
Die Datenbank kennt weder die Grenzen der Logical Unit of Work (des Use Case) noch die Aggregatgrenzen noch das akzeptable Mass an Inkonsistenz fuer Skalierbarkeit. Deshalb ist die Ablaufsteuerung in der Applikationsschicht die richtige Heimat der Transaktionssteuerung.
Isolation Levels und Inkonsistenzen
Read Uncommitted erlaubt Dirty, Non-Repeatable und Phantom Reads; Read Committed verhindert Dirty Reads; Repeatable Read verhindert Dirty und Non-Repeatable Reads; Serializable verhindert alle drei. Hoehere Isolation = mehr Konsistenz, aber schlechtere Skalierbarkeit durch gegenseitiges Blockieren.
Optimistisch vs. pessimistisch
Optimistisches Sperren: alle koennen aendern, wer zuerst schreibt gewinnt (Versionszaehler-Vergleich beim Speichern); der Zweitschreibende verliert seine Daten (Optimistic locking loser exception). Pessimistisches Sperren: genau ein Anwender kann aendern (Sperre pro Session und Aggregat mit Timeout), Konflikte werden verhindert.
Never trust the client / Zero Trust vs. Full Trust
Die vollstaendige Validierung und die feingranulare Berechtigungspruefung gehoeren an den Inbound Port der Applikationsschicht (Never trust the client). Der Client wird mit Zero Trust behandelt (grobe Pruefung schon am HTTP-Request als erste Verteidigungslinie), die Domaene ist Full Trust und prueft nicht.
Eingabe- vs. Invariantenvalidierung
Eingabevalidierungsfehler sind Teil der vorgesehenen Funktionalitaet, werden gesammelt/gebuendelt gemeldet und ergeben HTTP 4** Codes. Invariantenfehler sind immer Programmierfehler, werden einzeln geprueft und ergeben HTTP 5** Codes.
Warum DTO und nicht Werteobjekt zur Validierung
Zur Validierung braucht man Objekte, die die Daten aufnehmen, aber keine Invarianten garantieren. Werteobjekte wuerden bei invaliden Daten sofort eine Ausnahme werfen, deshalb werden DTOs verwendet.
Ausnahmen richtig uebersetzen
Outbound-Adapter uebersetzen technologiespezifische Ausnahmen in das Ausnahmemodell der Anwendung; Inbound-Adapter uebersetzen alle Ausnahmen in technologiespezifische (Client-)Fehler. Die Applikationsschicht darf keine technologiespezifischen Ausnahmen (z.B. TransformerException) kennen, sonst entsteht eine unzulaessige Abhaengigkeit.

Klausur-Stichworte (aus der Zusammenfassung)

Theißen hat gesagt: alle prüfbaren Themen tauchen als Stichwort in den Zusammenfassungs-Folien auf. Genau diese Stichworte stehen hier.

📌 Zusammenfassung dieses Kapitels
  • Bestandteile der Applikationsschicht: Inbound Ports, Outbound Ports, Data Transfer Objects
  • Inbound Ports sind die zentralen Objekte im Applikationshexagon; implementieren Interfaces vom Typ Use Cases (ISP)
  • Inbound Ports: nehmen Eingaben von Inbound Adaptern entgegen; nutzen Outbound Ports fuer externe Systeme, andere Komponenten und Datenbank
  • Inbound Ports: uebersetzen zwischen Domaenenmodell (Entitaeten, Werteobjekten) und DTOs; versorgen Domaenenobjekte mit Daten und Abhaengigkeiten
  • Inbound Ports kuemmern sich um: Sperren, Transaktionssteuerung, Berechtigungspruefung, Protokollierung/Logging, Ausnahmebehandlung, Validierung
  • Outbound Ports koennen Interfaces sein (von Outbound Adaptern oder Inbound Ports anderer Komponenten implementiert) oder Klassen (rufen Use Cases in anderen Komponenten auf)
  • DTOs: reine Datenobjekte aus Standardtypen ohne Verhalten; stellen keine Invarianten sicher; foerdern effizienten Datenaustausch ueber das Netzwerk; machen ISP vollstaendig; zwingend zur Validierung benoetigt
  • Ablaufsteuerung: Ablaufsteuerung von Anwendungsfaellen (Aufruf Domaenenlogik, Orchestrierung Infrastruktur-Zugriffe, Koordination mit anderen Komponenten/Anwendungen); DTO-Mapping
  • Transaktionssteuerung: Grundoperationen Starten – Commit – Rollback; Eigenschaften Read-Only-Hinweis, Isolation, Propagation
  • Sperren: Optimistisches Sperren (Konfliktpruefung beim Speichern); Pessimistisches Sperren (Konflikte verhindern)
  • Validierung Prinzipien: Nicht dem Client vertrauen; Aktiv validieren und nicht auf Ausnahmen warten; Am Anfang validieren (Eingabevalidierung in der Applikationsschicht)
  • Validierung Ablauf: alle Eingaben vollstaendig validieren; Fehler gesammelt und gebuendelt an den Client zurueckgeben
  • Validierungsregeln: fachliche Invarianten an die Domaenenschicht delegieren; Formatvalidierung selbst bereitstellen
  • Berechtigungspruefung: uebliches Modell Berechtigungen, Rollen, Gruppen, User; Pruefung auf Aktion und Aktion mit bestimmten Daten
  • Berechtigungspruefung: Zero Trust fuer den Client, Full Trust fuer die Domaene; zwei Verteidigungslinien HTTP-Request (grob, URL-Ebene) und Inbound Port (detaillierter); Modell einfach halten
  • Ausnahmebehandlung: anwendungseigene Ausnahmehierarchie meist erforderlich; Adapter der Infrastrukturschicht sind fuer Ausnahmenuebersetzung verantwortlich
  • Logging: Klarheit ueber den Zweck, aussagekraeftige Eintraege, sinnvolle und einheitliche Verwendung der Log-Ebenen; keine Geheimnisse loggen; Kontextinformationen bereitstellen; strukturierte Logdaten als Datenstrom
  • Protokollierung: minimale Auditinformationen created by/at, changed by/at; Option Aenderungen extrahieren; Option Aenderungen als eigenes Objekt betrachten

Übungsfragen

F1 Welche drei Schichten (Hexagone) hat eine Komponente in der Referenzarchitektur der logischen Sicht, und in welche Richtung zeigen die Codeabhaengigkeiten?

Eine Komponente besteht aus Infrastructure (*.infra) mit Inbound- und Outbound-Adaptern, Application (*.application) mit Inbound- und Outbound-Ports und Domain (*.domain) mit Wurzelentitaet, Aggregat, Entitaet, Wertobjekt, Domain Service und Domain Event. Die Codeabhaengigkeiten zeigen von aussen nach innen zur Domaene (Dependency Inversion Principle), sodass die Domaene keine aeusseren Schichten kennt.

F2 Worin unterscheiden sich die fachlichen von den querschnittlichen Aufgaben der Applikationsschicht?

Fachliche Aufgaben sind die Ablaufsteuerung von Anwendungsfaellen (Aufruf der Domaenenlogik, Koordination mit anderen Komponenten und Anwendungen, Orchestrierung der Infrastruktur-Zugriffe) sowie das DTO-Mapping. Querschnittliche Aufgaben sind Transaktionssteuerung, Sperrmechanismus, Validierung, Berechtigungspruefung, Ausnahmebehandlung, Logging und Protokollierung; sie fallen bei praktisch jedem Anwendungsfall an.

F3 Was ist ein Data Transfer Object und wie grenzt es sich von einem Wertobjekt (Value Object) ab?

Ein DTO fasst in einer verteilten Umgebung zu uebertragende Daten in einem eigenen Objekt zusammen, um die Anzahl der Netzwerkaufrufe zu reduzieren. Anders als ein Wertobjekt hat es nur den Zweck Daten zu transferieren, enthaelt keine Logik, ist aenderbar und garantiert nicht, dass seine Daten validiert sind. Ein Wertobjekt garantiert dagegen die Einhaltung seiner Invarianten.

F4 Warum verwendet man zur Eingabevalidierung DTOs und nicht direkt Wertobjekte?

Zur Validierung braucht man Objekte, die die eingehenden Daten aufnehmen koennen, ohne den Anspruch zu erheben, Invarianten einzuhalten. Wertobjekte garantieren ihre Invarianten und wuerden bei invaliden Daten sofort eine Ausnahme werfen, bevor man ueberhaupt eine aussagekraeftige, gesammelte Fehlermeldung erzeugen koennte. Deshalb nimmt man DTOs, die noch nicht validierte Daten tragen.

F5 Warum reicht es nicht aus, die Transaktionssteuerung allein der Datenbank zu ueberlassen?

Die Datenbank fuehrt zwar jedes Statement transaktional aus und macht Auto-Commit, weiss aber nicht, welche weiteren Statements zur selben Logical Unit of Work (demselben Use Case) gehoeren, wo die Grenzen eines Aggregates liegen und wieviel Inkonsistenz fuer bessere Skalierbarkeit akzeptabel ist. Transaktionssteuerung ist fachlich getrieben und gehoert daher in die Ablaufsteuerung der Applikationsschicht.

F6 Welche vier Eigenschaften steuern das Verhalten einer Transaktion, und wozu dient der Read-Only-Hinweis?

Die vier Eigenschaften sind Read-Only, Timeout, Isolation und Propagation. Der Read-Only-Hinweis zeigt an, dass die Transaktion keine schreibenden Zugriffe macht; das kann die Datenbank selbst nicht wissen. Er verhindert Sperren von Tabelleneintraegen und erlaubt Optimierungen im Persistenz-Framework, sodass z.B. eine zweite lesende Transaktion nicht warten muss.

F7 Nennen Sie die drei Arten von Inkonsistenzen und geben Sie an, welche Isolation Levels sie jeweils verhindern.

Dirty Reads (Lesen noch nicht committeter Aenderungen), Non-Repeatable Reads (ein erneuter Lesevorgang liefert nach fremdem Commit ein anderes Ergebnis) und Phantom Reads (ein erneuter Lesevorgang liefert nach fremdem Insert-Commit zusaetzliche Zeilen). Read Committed verhindert Dirty Reads, Repeatable Read zusaetzlich Non-Repeatable Reads, und Serializable verhindert alle drei; Read Uncommitted verhindert keine.

F8 Was beschreibt das Propagationsverhalten einer Transaktion, und welches Problem loest es?

Propagation legt fest, wie sich eine transaktionale Methode gegenueber einer bereits bestehenden Transaktion verhaelt, etwa ob sie eine vorhandene weiterfuehrt oder eine neue beginnt. Es loest das Problem, dass ein wiederverwendeter Use Case (z.B. Mitarbeiter laden) keine eigene Transaktion starten und beenden soll, weil sonst der aufrufende Use Case (z.B. Praemie auszahlen) das Ergebnis nicht in derselben Transaktion weiterverwenden koennte.

F9 Warum genuegen Datenbanktransaktionen allein nicht fuer Datenkonsistenz bei mehreren Benutzern?

Weil das Lost-Update-Problem auftreten kann: Zwei Anwender lesen denselben Datensatz, der erste aendert und speichert, danach aendert und speichert der zweite und ueberschreibt dabei die Aenderungen des ersten, selbst wenn er andere Felder geaendert hat. Deshalb braucht man zusaetzlich einen Sperrmechanismus als Grundvoraussetzung fuer Mehrbenutzerfaehigkeit.

F10 Vergleichen Sie optimistisches und pessimistisches Sperren hinsichtlich Regel, Vor- und Nachteilen.

Pessimistisch gilt die Regel, dass genau ein Anwender aendern darf; eine Sperre wird pro Session und Aggregat gesetzt (mit Timeout). Vorteil ist das garantierte Aendern, Nachteil der noetige Editiermodus und die Behinderung anderer. Optimistisch gilt, dass alle aendern duerfen und wer zuerst schreibt gewinnt; ueber einen Versionszaehler wird beim Speichern verglichen. Vorteile sind kein Editiermodus, keine Blockade und Einfachheit, Nachteil ist der Datenverlust des Zweitschreibenden.

F11 Worin unterscheiden sich Eingabevalidierung und Invariantenvalidierung?

Die Eingabevalidierung prueft, ob der Input in die Anwendung korrekt ist; sie fuehrt alle Pruefungen vollstaendig aus, sammelt Fehler und meldet sie gebuendelt (Codes fuer I18N), ist Teil der vorgesehenen Funktionalitaet und fuehrt bei HTTP zu 4**-Codes. Die Invariantenvalidierung prueft an diversen Stellen innerhalb der Anwendung einzeln, sammelt keine Fehler, hat Texte im Code und deutet immer auf Programmierfehler hin, was bei HTTP zu 5**-Codes fuehrt.

F12 An welcher Stelle im hexagonalen Modell gehoert die vollstaendige Validierung hin und warum gerade dort?

Die vollstaendige Validierung (Format- und fachliche Validierung) gehoert in die Applikationsschicht an den Inbound Port, nach dem Grundsatz Never trust the client. Dort liegen DTOs mit noch nicht validierten Daten vor, es besteht Zugriff auf Datenbank (via Outbound Port) und Domaenenlogik (Validierungsregeln) und es ist bereits eine Transaktion vorhanden. Der Adapter validiert nur den Datentyp, und das UI validiert lediglich zum Bedienkomfort.

F13 Warum werden Rollen und zusaetzlich Gruppen zur Berechtigungsvergabe verwendet?

Rollen buendeln fachlich zusammengehoerige Berechtigungen, sodass man weniger Berechtigungsdaten pflegen muss; allerdings befinden sich Rollen im Code. Gruppen entkoppeln davon: Man haelt Rollen feingranular und ordnet sie Gruppen zu, die den Taetigkeitsprofilen entsprechen und ausserhalb der Anwendung in einem Unternehmensverzeichnis anwendungsuebergreifend gepflegt werden. So erfordern geaenderte Taetigkeitsprofile keine Codeaenderung mehr.

F14 Was bedeuten Zero Trust und Full Trust im Kontext der Berechtigungspruefung, und wo liegen die zwei Verteidigungslinien?

Zero Trust gilt fuer den Client, der grundsaetzlich als nicht vertrauenswuerdig gilt; Full Trust gilt fuer die Domaene, die annimmt, immer mit geprueften Berechtigungen aufgerufen zu werden, und daher nicht prueft. Die erste Verteidigungslinie ist der HTTP-Request im Adapter mit grobgranularer Pruefung auf HTTP-Methode und URL, die zweite der Inbound Port mit feingranularer Pruefung auf Use Case und Daten.

F15 Warum ist es ein Verstoss gegen die Abhaengigkeitsregeln, wenn die Applikationsschicht eine TransformerException faengt, und wie loest man das Problem?

Die TransformerException ist eine technologiespezifische Ausnahme aus der JAXP-Bibliothek; wenn die Applikationsschicht sie faengt, haengt sie von technologiespezifischem Code ab, weil die Kapselung durch den Adapter bei den geworfenen Ausnahmen eine Luecke hat. Die Loesung ist, dass Outbound-Adapter technologiespezifische Ausnahmen in das anwendungseigene Ausnahmemodell uebersetzen, sodass die Applikation nur dieses Modell kennt.

F16 Welche Log-Ebenen richten sich an den Betrieb und welche an die Entwicklung, und was bedeuten ERROR und INFO?

Fuer den Betrieb sind FATAL, ERROR, WARN und INFO gedacht, fuer die Entwicklung DEBUG und TRACE (sie steuern die Granularitaet). ERROR bezeichnet einen Fehler, der die Weiterverarbeitung eines Vorgangs unmoeglich macht, ausdruecklich aber kein Validierungsfehler. INFO bezeichnet ein relevantes fachliches Ereignis, zum Beispiel dass eine Entitaet angelegt wurde oder ein Statusuebergang stattfand.

F17 Wofuer dienen Korrelations-ID und Span-ID beim Logging in verteilten Systemen?

Die Korrelations-ID ist eine im verteilten System eindeutige ID pro urspruenglichem Request und dient dazu, alle zu diesem Request gehoerenden Logeintraege ueber mehrere Services hinweg zuzuordnen. Die Span-ID wird pro Thread vergeben und erlaubt es, die Reihenfolge unabhaengig von Zeitstempeln zu rekonstruieren; beide werden als HTTP-Request-Header weitergegeben.

F18 Was ist der Mapped Diagnostic Context (MDC) und wozu wird er verwendet?

Der MDC ist ein Mechanismus, um Kontextinformationen beim Logging bereitzustellen, die lokal an der Log-Stelle nicht vorhanden sind, etwa HTTP-Request-Pfad, User-ID, Use Case oder Objekt-ID. Die Informationen werden als Key-Value-Paare pro Thread gespeichert (z.B. im Inbound Adapter und Inbound Port gesetzt) und muessen am Ende mit MDC.clear() geloescht werden, damit keine veralteten Kontextinformationen im Thread verbleiben.

F19 Welche zwei grundsaetzlichen Ansaetze zur Protokollierung von Aenderungen nennt die Vorlesung?

Ansatz 1 schreibt Aenderungen mit: minimale Auditinformationen in der Entitaet (created by/at, changed by/at) und optional eine vollstaendige Historie ueber Aenderungstabellen oder eine versionierte Datenbank (z.B. Hibernate Envers). Ansatz 2 betrachtet eine Aenderung als eigenes Objekt, die sogenannte Geschaeftstransaktion (Business Transaction), die alle Informationen zum Abarbeiten des Auftrags enthaelt und sowohl zur Ausfuehrung als auch zur Protokollierung gespeichert wird.

F20 Was ist eine Geschaeftstransaktion (Business Transaction) und wie unterscheidet sie sich von einer Datenbanktransaktion?

Eine Geschaeftstransaktion ist ein eigenes Objekt, das eine Aenderung als Auftrag repraesentiert und alle Informationen zum Abarbeiten enthaelt, zum Beispiel ChangeEmployeeAddressTransaction mit Transaktionsnummer, Zeitstempel, User, Personalnummer und neuer Adresse. Sie hat nichts mit einer Datenbanktransaktion zu tun: Sie wird zweifach genutzt, naemlich zum Abarbeiten des Auftrags und, gespeichert, zur Protokollierung.

F21 Warum duerfen Entitaeten die Komponente nicht verlassen, und welche Sonderstellung hat die Datenbank?

Entitaeten werden nach aussen nicht exponiert; zwischen Komponenten und gegenueber dem Client werden stattdessen DTOs oder Werteobjekte ausgetauscht, um das Domaenenmodell zu kapseln. Eine Ausnahme bildet die Datenbank: Ihre Daten sind bereits validiert, sie hat eine Sonderstellung, und deshalb duerfen Entitaeten gegenueber der Datenbank exponiert werden, sodass der JPA-Outbound-Adapter beim Lesen eine Entitaet statt eines DTO zurueckgibt.

F22 Welche Rolle spielt das Interface Segregation Principle (ISP) fuer Use-Case-Interfaces und DTOs im Applikationshexagon?

Nach dem ISP bekommt jeder Client sein eigenes Use-Case-Interface (z.B. PayrollEmployeeUseCases, HREmployeeUseCases, SelfServiceEmployeeUseCases) und seine eigenen DTOs, sodass Clients nicht ueber gemeinsam verwendete Methoden, Parameter oder Rueckgabewerte voneinander abhaengen. Erst durch eigene DTOs wird das ISP vollstaendig, weil jede Schnittstelle dann genau ihre eigenen Methoden und Daten besitzt.