Clean Architecture Protocols
Relevant source files
The following files were used as context for generating this wiki page:
Clean Architecture Protocols in FLEXT-Core provide a set of foundational structural types and interfaces that enforce architectural boundaries across the monorepo. By utilizing Python's typing.Protocol and @runtime_checkable decorators, these protocols allow for loose coupling between components while maintaining strict type safety and adherence to the Interface Segregation Principle.
The protocol system is organized into a hierarchical namespace, primarily starting with FlextProtocolsBase, which serves as the root for foundational primitives. These protocols ensure that domain models, services, and infrastructure components can interact through well-defined structural contracts without creating circular dependencies.
Sources: src/flext_core/_protocols/base.py:1-20, src/flext_core/init.py:1-50
Foundational Protocols
The core of the protocol system is built on foundational primitives that define basic structural markers and utility interfaces. These are designed to be used by infrastructure helpers and decorators to interact with various runtime values.
Base and Attribute Probing
The system defines a Base protocol for all structural types and an AttributeProbe protocol. The AttributeProbe is a structural marker for values inspected via hasattr or getattr, allowing infrastructure to handle objects carrying inspectable attributes without resorting to Any.
The diagram shows the basic hierarchy of core protocols used for structural typing and attribute inspection.
Sources: src/flext_core/_protocols/base.py:23-45
Core Structural Types
| Protocol | Purpose | Key Attributes/Methods |
|---|---|---|
ModuleOwned | Ensures symbols expose their owner module. | __module__ |
FieldInfoLike | Structural contract for Pydantic v2 field metadata. | default, description, title |
Model | Structural typing for Pydantic v2 models to avoid circular imports. | model_fields, model_dump(), model_validate() |
ConfigObject | Mapping-like interface for configuration payloads. | get(), keys(), items() |
Sources: src/flext_core/_protocols/base.py:47-159
Messaging and Execution Protocols
FLEXT-Core defines protocols for routable messages and executable service components, facilitating CQRS (Command Query Responsibility Segregation) and standardized service execution.
Routable Interfaces
Messages within the system are categorized by their routing behavior. The Routable protocol acts as a base for specific message types:
- CommandRoutable: Carries a
command_type. - EventRoutable: Carries an
event_type. - QueryRoutable: Carries a
query_type.
The flowchart illustrates the relationship between the base Routable protocol and its specialized CQRS counterparts.
Sources: src/flext_core/_protocols/base.py:175-201
Service Execution
The Executable protocol defines objects that can be executed and report service information. This is a primary interface for service-layer components.
@runtime_checkable
class Executable(Base, Protocol):
"""Protocol for objects that can be executed and report service info."""
def execute(
self,
) -> p.Result[t.JsonPayload]: ...
def service_info(self) -> t.JsonMapping: ...
Sources: src/flext_core/_protocols/base.py:203-211
Domain-Driven Design (DDD) Protocols
To support Domain-Driven Design, the protocol layer includes specialized interfaces for Aggregate Roots and domain event management.
Aggregate Roots and Events
The HasDomainEvents protocol is designed for DDD aggregate roots. It requires an identity (unique_id) and a buffer for uncommitted events (domain_events). This protocol allows utilities to interact with entities for event propagation without knowing the specific entity implementation.
| Field | Type | Description |
|---|---|---|
unique_id | str | Unique identity of the aggregate root. |
domain_events | MutableSequence[m.DomainEvent] | A sequence buffering uncommitted domain events. |
Sources: src/flext_core/_protocols/base.py:239-249
Protocol Organization and Implementation
Protocols are organized into multiple parts and aggregated into facades. This structure allows the framework to scale while maintaining specific categories of protocols like Result, Context, Logging, and Settings.
Facade Structure
The FlextProtocols facade (often aliased as p) composes specialized protocol parts through inheritance. This is evident in the lazy-loading implementation and the test protocol extensions.
The sequence diagram shows how the facade system resolves protocols via lazy imports to minimize startup time and circular dependencies.
Sources: src/flext_core/_protocols/init.py:1-60, tests/protocols.py:25-45
Test Protocols
The testing suite extends the core protocols via TestsFlextProtocols. This allows for project-specific structural typing for test helpers, such as callables for transformations, mapping, and field extraction.
Sources: tests/protocols.py:35-125
Conclusion
Clean Architecture Protocols in FLEXT-Core establish a rigid yet flexible structural foundation. By defining these interfaces, the framework ensures that components—ranging from Pydantic models to DDD aggregates—adhere to standard behaviors, enabling robust dependency injection and observability across the ecosystem.
Sources: src/flext_core/_protocols/base.py, src/flext_core/init.py