Python · architecture
require-port-for-service
python:require-port-for-service Consider a consumer-owned port for a service with a behaviorally used collaborator.
- Code
- SARJ071
- Default
- error
- Fix
- none
- Languages
- python
Why
A small port can decouple consumers when they genuinely need to substitute a concrete service boundary.
Fix
Define a focused `Protocol` or ABC and type substituting consumers against it, or suppress the advisory when no substitution boundary exists.
Before / after
Executed by this rule’s unit tests.
Before
Concrete service directly exposes an injected collaborator
class ThingService:
def __init__(self, client: ThingClient) -> None:
self.client = client
def read(self, key: str) -> str:
return self.client.get(key)
def write(self, key: str, value: str) -> None:
self.client.put(key, value)
After
Service implements a declared port
class ThingService(ThingServicePort):
def __init__(self, client: ThingClient) -> None:
self.client = client
def read(self, key: str) -> str:
return self.client.get(key)
def write(self, key: str, value: str) -> None:
self.client.put(key, value)
Limits
- This advisory uses service-family names, constructor annotations, collaborator calls, and public-method counts as heuristics.
- Tests, generated code, scripts, known framework shapes, persistence-only dependencies, and classes with declared bases are excluded.