attack-on-domain¶
attack-on-domain
DDD building blocks for Python 3.14+
Build maintainable domain models with entities, value objects, aggregates, CQRS, and hexagonal architecture — fully typed, immutable, with built-in validation, and designed for real-world applications.
Key Features¶
Domain Building Blocks
Entity, RootEntity, ValueObject, and Aggregate — everything you need to model your business domain with identity, mutation guards, and consistency boundaries.
Domain Events
Immutable, auto-timestamped records of domain occurrences. Automatically collected by use cases.
CQRS
CQRS-based architecture with easy-to-implement commands, queries, and handlers.
Use Cases
Application-layer operations with auto-wired ports, event collection, logging, and transaction management.
Business Invariants
Enforce domain rules at construction time with type-safe field and model-level invariants that raise clear domain exceptions.
Testing
Spy containers, session stubs, fakers, and event assertions — everything you need to test your domain, application, and infrastructure layers.
Quick Example — Use Case with CQRS and Dependency Injection¶
from aod.domain import RootEntity, ValueObject
from aod.events import Event
from aod.application import UseCase, Command, CommandPort
from aod.infrastructure import CommandHandler, Session, AdapterContainer
class SqlSession(Session):
def execute(self, operation: object) -> None: ...
class OrderId(ValueObject):
value: str
class Order(RootEntity):
id: OrderId
total: float
class OrderPlaced(Event):
order_id: str
total: float
class PlaceOrder(Command[Order, None]):
order_id: str
total: float
class PlaceOrderHandler(CommandHandler[PlaceOrder]):
session: SqlSession
def handle(self, command: PlaceOrder) -> None:
order = Order(id=OrderId(value=command.order_id), total=command.total)
self.session.execute(order)
class PlaceOrderUseCase(UseCase):
place_order: CommandPort[PlaceOrder]
def run(self, order_id: str, total: float) -> None:
self.place_order.handle(PlaceOrder(
order_id=order_id, total=total,
))
container = AdapterContainer(handlers=[PlaceOrderHandler])
use_case = container.adapt(PlaceOrderUseCase)
use_case.run(order_id="1", total=99.99)
Architecture¶
The library follows hexagonal architecture (ports and adapters) combined with DDD layers:
| Layer | Components | Depends On |
|---|---|---|
| Infrastructure | Handlers, Session, Container, Projection | Application |
| Application | UseCase, Port, Command, Query | Domain |
| Domain | Entity, ValueObject, Service, Event | None - (pure business logic) |
Each layer depends only on the layer below it:
- Domain — Pure business logic with no infrastructure dependencies
- Application — Orchestrates domain objects through Port interfaces
- Infrastructure — Implements ports for databases, APIs, and other external systems
Next Steps¶
Quick Start
Get up and running in 5 minutes with a complete example.
DDD Concepts
Learn the Domain-Driven Design principles behind the library.
Building Blocks
Entities, Value Objects, Services, and more.
Testing
Utilities for testing your domain, application, and infrastructure.