7 min readCalm pace · scan the outline anytime

Cross-module ACL

Sync Anti-Corruption Layer — local port plus adapter to a thin peer ModuleInterface.

Cross-module ACL (sync)

Purpose: when a Use Case needs another module’s answer in the same request.

Illustrative example: Ordering checks stock via WarehouseAvailabilityPortInterfaceWarehouseAvailabilityAclAdapter → thin WarehouseAvailabilityModuleInterface (or a small WarehouseModuleInterface).

Failure / transaction rules: Transactions and failures. Façade thinness: Cross-module contracts.

Two different ports

PortName patternOwned byInjected into
Local (inbound need){Need}PortInterfaceConsumerConsumer Use Cases
Outbound façade{This}ModuleInterface or capability-sized *ModuleInterfaceProviderPeer ACL adapters only — never peer Use Cases

Keep façades thin and HTTP-mappable. Split when the surface grows (contracts).

Sequence — place order checks availability

Why mapping exists

Warehouse speaks Warehouse language (location codes, reservation statuses). Ordering Application/Domain must not import those types. The adapter converts:

  • Peer codes → values Ordering stores on lines
  • Availability flags → booleans or local result DTOs
  • Failures → exceptions / results the Ordering Use Case can apply policy to

Folder layout (both sides)

# Consumer (Ordering)
Domain/Ports/Acl/WarehouseAvailabilityPortInterface.php
Infrastructure/ExternalServices/WarehouseAvailabilityAclAdapter.php
Application/Providers/…   # bind local port → adapter

# Provider (Warehouse)
Domain/Ports/Module/WarehouseAvailabilityModuleInterface.php
Application/Providers/…   # bind ModuleInterface → implementation

Replaceability test

If Ordering Use Cases already type-hint the Warehouse *ModuleInterface, the test fails.

Anti-patterns

Anti-patternFix
use …Warehouse\… inside Ordering Use CaseLocal port + ACL
Injecting peer *ModuleInterface into Ordering Use CaseSame
God WarehouseModuleInterface with dozens of unrelated methodsSplit capability façades
Conversion logic in Use Case with foreign enumsKeep conversion in adapter
Shared business enum in Shared kernel “for reuse”Never Shared for business concepts
Peer write + local commit with no failure storyTransactions

Next: cross-module events · contracts.

Modular Hexagonal Domain-Driven Design
Core 1.0.0-draft