ADR-002: Protocol-Based Ports Instead of ABCs#
Status#
Accepted
Context#
Hexagonal architecture defines ports as abstract interfaces that adapters implement. Python offers two mechanisms for this:
abc.ABCwith@abstractmethod— nominal subtyping. Implementations must explicitly inherit from the abstract class.typing.Protocol— structural subtyping. Any class with matching method signatures satisfies the protocol without explicit inheritance.
The project has two ports: LLMPort (LLM provider interface) and
OrchestratorPort (analysis strategy interface). Each has exactly one
method.
Decision#
Use typing.Protocol for both LLMPort and OrchestratorPort.
Implementation explicitly inherit the Port protocol class.
Options Considered#
Option A: abc.ABC (rejected)#
Pro: Explicit inheritance makes the relationship visible in the code. Forgetting to implement a method raises
TypeErrorat class definition time.Con: Requires import of the ABC in every adapter module, creating a compile-time coupling between the infrastructure layer and the domain layer. For two single-method interfaces, the ceremony of
class MyAdapter(LLMPort):adds no clarity over a matching method signature.
Option B: typing.Protocol (chosen)#
Pro: Structural subtyping — any class with the right method signature satisfies the contract. No import needed in adapter code (though it can still be imported for documentation). Lighter, more Pythonic. Static type checkers (
mypy,ty) verify conformance without runtime overhead.Con: No runtime
TypeErrorif a method is missing — the error surfaces at call time or during type checking, not at class definition time.Mitigation: The project uses
tyfor type checking in CI. Conformance is verified on every push.
Consequences#
Port definitions in
domain/ports.pyareProtocolclasses.Adapter classes DO inherit from ports.
Type checkers verify conformance. Tests verify behavior.
Adding a new adapter requires matching the protocol’s method signature.
Participants#
Devil’s advocate (proposed Protocol as lighter alternative)
Architect (accepted — ABCs add no value for single-method interfaces)