hides its implementation/a decision behind an interface. interface Study it without reading the rest. implementation e.g. a method, a class, a bounded context hschwentner.io hidden
object model •Inner layers define interfaces. Outer layers implement interfaces •Direction of coupling is toward the center •All application core code can be compiled and run separate from infrastructure ! hschwentner.io Jeffrey Palermo !
model use case repository interface service programming language domain library entity domain event value object ORM file system access data model repository implementation hschwentner.io l b g n i d l i l e bu lev
a survey of what exists. Prescription, not description à The current architecture lives in ARCHITECTURE.md ## Style - Hexagonal, not layered. Adapters depend inward; the domain depends on nothing. [DependencyRulesTest] - Domain imports no framework types. [DomainPurityTest] - One module per bounded context; modules talk through published interfaces, never through each other's tables. [ModuleApiTest] Style, not domain. ## Choices, where others are also reasonable - Ports live beside the domain, not in their own package. [PortLocationTest] - Mapping is hand-written. No MapStruct. [no test] - Persistence returns domain types, not entities. [no test] The contexts and their language live in CONTEXT-MAP.md. ## Enforcement Every rule here is an ArchUnit test. Rules marked [no test] are not yet enforced: if you touch code they govern, write the test first. Make it fail, then fix the code. Where a test and this file disagree, the file wins — fix the test. Where code breaks a rule and the suite stays green, the test is missing. All can be referenced from AGENTS.md. ## Known deviations - sales reads risk tables directly (owner: HS, #412). Do not add to this. New code goes through the port. hschwentner.io
their How this system should be built. language live in CONTEXT## Style MAP.md. - Hexagonal, not layered. Adapters depend inward; the # Architecture Rules How this system is built. Not a survey of what exists. Not a survey of what exists. domain depends on nothing. [DependencyRulesTest] - Domain imports no framework types. [DomainPurityTest] - One module per bounded context; modules talk through published interfaces, never through each other's tables. [ModuleApiTest] Both referenced from AGENTS.md. ## Choices, where others are also reasonable - Ports live beside the domain, not in their own package. [PortLocationTest] - Mapping is hand-written. No MapStruct. [no test] - Persistence returns domain types, not entities. [no test] ## Enforcement Every rule here is an ArchUnit test. Rules marked [no test] are not yet enforced: if you touch code they govern, write the test first. Make it fail, then fix the code. Where a test and this file disagree, the file wins — fix the test. Where code breaks a rule and the suite stays green, the test is missing. ## Known deviations - sales reads risk tables directly (owner: HS, #412). Do not add to this. New code goes through the port. hschwentner.io
a survey of what exists. ## Style Style, not domain. The contexts and their language live in CONTEXTdepend inward; the domain depends MAP.md. ## Style - Hexagonal, not layered. Adapters depend inward; the domain depends on nothing. [DependencyRulesTest] - Domain imports no framework types. [DomainPurityTest] - One module per bounded context; modules talk through published interfaces, never through each other's tables. [ModuleApiTest] - Hexagonal, not layered. Adapters on nothing. ## Choices, where others are also reasonable - Ports live beside the domain, not in their own package. [PortLocationTest] - Mapping is hand-written. No MapStruct. [no test] - Persistence returns domain types, not entities. [no test] [DependencyRulesTest] Both referenced from AGENTS.md. - Domain imports no framework types. [DomainPurityTest] - One module per bounded context; ## Enforcement Every rule here is an ArchUnit test. Rules marked [no test] are not yet enforced: if you touch code they govern, write the test first. Make it fail, then fix the code. Where a test and this file disagree, the file wins — fix the test. Where code breaks a rule and the suite stays green, the test is missing. modules talk through published interfaces. [ModuleApiTest] ## Known deviations - sales reads risk tables directly (owner: HS, #412). Do not add to this. New code goes through the port. hschwentner.io
a survey of what exists. ## Choices, where others are also reasonable ## Style - Hexagonal, not layered. Adapters depend inward; the domain depends on nothing. [DependencyRulesTest] - Domain imports no framework types. [DomainPurityTest] - One module per bounded context; modules talk through published interfaces, never through each other's tables. [ModuleApiTest] Style, not domain. The contexts and their language live in CONTEXT- Ports live beside the domain.MAP.md. ## Choices, where others are also reasonable - Ports live beside the domain, not in their own package. [PortLocationTest] - Mapping is hand-written. No MapStruct. [no test] - Persistence returns domain types, not entities. [no test] [PortLocationTest] Both referenced from - Mapping is hand-written. No MapStruct. AGENTS.md. [no test] ## Enforcement Every rule here is an ArchUnit test. Rules marked [no test] are not yet enforced: if you touch code they govern, write the test first. Make it fail, then fix the code. Where a test and this file disagree, the file wins — fix the test. Where code breaks a rule and the suite stays green, the test is missing. - Persistence returns domain types. [no test] ## Known deviations - sales reads risk tables directly (owner: HS, #412). Do not add to this. New code goes through the port. What the model cannot guess. hschwentner.io
a survey of what exists. ## Style - Hexagonal, not layered. Adapters depend inward; the domain depends on nothing. [DependencyRulesTest] - Domain imports no framework types. [DomainPurityTest] - One module per bounded context; modules talk through published interfaces, never through each other's tables. [ModuleApiTest] Style, not domain. ## Enforcement The contexts and their language live in CONTEXT- Ports live beside the domain, not in their own Rules marked [no test] are not yet MAP.md. package. [PortLocationTest] Every rule here is an ArchUnit test. ## Choices, where others are also reasonable - Mapping is hand-written. No MapStruct. [no test] - Persistence returns domain types, not entities. [no test] enforced: if you touch code they Both referenced from govern, write the test first. ## Enforcement Every rule here is an ArchUnit test. Rules marked [no test] are not yet enforced: if you touch code they govern, write the test first. Make it fail, then fix the code. Where a test and this file disagree, the file wins — fix the test. Where code breaks a rule and the suite stays green, the test is missing. AGENTS.md. Make it fail, then fix the code. Where a test and this file disagree, ## Known deviations - sales reads risk tables directly (owner: HS, #412). Do not add to this. New code goes through the port. the file wins - fix the test. Suite green on broken rule? Test missing. hschwentner.io
a survey of what exists. ## Style - Hexagonal, not layered. Adapters depend inward; the domain depends on nothing. [DependencyRulesTest] - Domain imports no framework types. [DomainPurityTest] - One module per bounded context; modules talk through published interfaces, never through each other's tables. [ModuleApiTest] ## Known deviations ## Choices, where others are also reasonable - Ports live beside the domain, not in their own package. [PortLocationTest] - Mapping is hand-written. No MapStruct. [no test] - Persistence returns domain types, not entities. [no test] - sales reads risk tables directly. owner: HS, issue #412 ## Enforcement Every rule here is an ArchUnit test. Rules marked [no test] are not yet enforced: if you touch code they govern, write the test first. Make it fail, then fix the code. Where a test and this file disagree, the file wins — fix the test. Where code breaks a rule and the suite stays green, the test is missing. Do not add to this. New code goes through ## Known deviations - sales reads risk tables directly (owner: HS, #412). Do not add to this. New code goes through the port. the port. Honest about what is already broken. hschwentner.io
Edsger. “Go To Statement Considered Harmful.” Communications of the ACM 11, no. 3 (March 1968): 147–48. Evans, Eric. Domain-Driven Design: Tackling Complexity in the Heart of Software. Boston: Addison-Wesley, 2004. Lilienthal, Carola and Henning Schwentner. Domain-Driven Transformation: Modernize Legacy Software and Mitigate Risk. Santa Rosa, CA: O’Reilly, 2026. Parnas, David L. “On the Criteria To Be Used in Decomposing Systems into Modules.” Communications of the ACM 15, no. 12 (December 1972): 1053–58. Yourdon, Edward and Larry L. Constantine. Structured Design: Fundamentals of a Discipline of Computer Program and Systems Design. New York: Yourdon Press, 1979. hschwentner.io
https://hschwentner.io in/henningschwentner [email protected] en v i r D ain-mation m o D sfor Tran Legac rnize Mode nd ems a y Syst k te Ris Mitiga al & ienth ner t la Lil Caro Schwen thers g a in Fe h ae l H en n ic by M word Fore