Package diagram — ports and adapters, with the ArchUnit rule that enforces it
UML package diagram of a Java service laid out as hexagonal / ports-and-adapters architecture, showing every compile-time «use» and «realise» dependency between adapter, application and domain packages together with the ArchUnit layeredArchitecture test that fails the build when an arrow points outward.
Rendering…
Make it your own.
#direction: right
#spacing: 46
#padding: 10
#fontSize: 11
#edges: rounded
[<frame>com.acme.orders — ports and adapters|
[<package>adapter.in.web|
OrderController
PlaceOrderRequest
OrderResponseMapper]
[<package>adapter.in.messaging|
PaymentAuthorisedListener
OrderEventDeserializer]
[<package>application.port.in|
«interface» PlaceOrderUseCase
«interface» CancelOrderUseCase]
[<package>application.port.out|
«interface» LoadOrderPort
«interface» SaveOrderPort
«interface» AuthorisePaymentPort]
[<package>application.service|
PlaceOrderService
CancelOrderService]
[<package>domain.model|
Order
OrderLine
Money
OrderStatus]
[<package>adapter.out.persistence|
OrderJpaRepository
OrderEntity
OrderEntityMapper]
[<package>adapter.out.payment|
StripePaymentGateway
StripeErrorTranslator]
[adapter.in.web] --> [application.port.in]
[adapter.in.messaging] --> [application.port.in]
[application.service] --:> [application.port.in]
[application.service] --> [application.port.out]
[application.service] --> [domain.model]
[adapter.out.persistence] --:> [application.port.out]
[adapter.out.payment] --:> [application.port.out]
[adapter.out.persistence] --> [domain.model]
[application.port.in] --> [domain.model]
[application.port.out] --> [domain.model]
]
[<note>Enforced by OrdersArchitectureTest (ArchUnit 1.x):
layeredArchitecture().consideringAllDependencies()
.layer("domain").definedBy("com.acme.orders.domain..")
.layer("application").definedBy("com.acme.orders.application..")
.layer("adapter").definedBy("com.acme.orders.adapter..")
.whereLayer("adapter").mayNotBeAccessedByAnyLayer()
.whereLayer("application").mayOnlyBeAccessedByLayers("adapter")
.whereLayer("domain").mayOnlyBeAccessedByLayers("application", "adapter")
Dashed open arrows are «use» dependencies, hollow triangles «realise».
Every arrow points inward: domain.model imports nothing but the JDK.] -- [<frame>com.acme.orders — ports and adapters]