Internal Block Structure¶
How forging-blocks is organized internally¶
This section describes how forging-blocks itself is structured into blocks — named groups of code sharing a responsibility and boundary. It documents the library's own internal organization, not a prescription for how you should structure your project.
The library's block names are its own convention
The library's five internal blocks (foundation, domain, application,
infrastructure, presentation) are an organizational convention, not a
naming template.
The toolkit itself is architecture-agnostic — you are free to interpret blocks as layers or any other structure.
Your own project's blocks should carry names meaningful to your context — core, domain, or a
domain-specific term — rather than replicating the library's internal naming.
Quick summary¶
The forging-blocks library is organized into five blocks, each with a distinct responsibility:
- Foundation — Reusable low-level abstractions (
Result,Port,Mapper, errors, meta utilities). No dependencies. - Domain — Problem space concepts (Entities, Value Objects, Aggregates, Domain Errors). Depends only on Foundation.
- Application — Orchestration contracts (Use Cases, Message Handlers, Inbound/Outbound Ports). Depends on Domain + Foundation.
- Infrastructure — Technology-agnostic implementations (in-memory repos, OS filesystem, stdlib logging). Implements Application's outbound ports.
- Presentation — Entry-point abstractions (adapters, middleware, error handling). Calls Application; stays thin.
Dependency rules (inward-pointing): Foundation has no deps → Domain depends on Foundation → Application depends on Domain + Foundation; Infrastructure and Presentation depend on Application + Foundation.
Block ≠ Layer
Blocks are architecture-neutral named boundaries within the library; they can be interpreted as layers if that mental model helps.
The library's five blocks and their dependency relationships:
- Foundation – reusable, low-level abstractions.
- Domain – problem-space concepts and rules.
- Application – workflow contracts and coordination abstractions.
- Infrastructure – technology-agnostic adapter implementations.
- Presentation – entry-point and interaction abstractions.
flowchart TD
P[Presentation]
A[Application]
D[Domain]
I[Infrastructure]
F[Foundation]
P -->|Calls| A
A -->|Coordinates| D
A -->|Delegates to| I
D -->|Builds on| F
A -->|Builds on| F
I -->|Builds on| F
P -->|Builds on| F
I -->|Builds on| A
%% --- Node styling ---
style P fill:#3c3836,stroke:#fabd2f,color:#ebdbb2 %% Presentation: Dark Gray, Yellow Outline
style A fill:#504945,stroke:#fabd2f,color:#ebdbb2 %% Application: Darker Gray, Yellow Outline
style D fill:#665c54,stroke:#fe8019,color:#ebdbb2 %% Domain: Muted Brown, Orange Outline
style I fill:#454157,stroke:#b8bb26,color:#ebdbb2 %% Infrastructure: Dark Violet, Olive Green Outline
style F fill:#665c54,stroke:#fb4934,color:#ebdbb2 %% Foundation: Muted Brown, Vibrant Red Outline
This diagram illustrates how the library's blocks relate to each other.
Block vs Layer¶
In forging-blocks, a block is an architecture-neutral concept — a named group of code sharing a responsibility and boundary.
Blocks can be mentally mapped to layers if that model is familiar: Foundation maps to a shared kernel, Domain and Application map to a core (business logic), and Infrastructure and Presentation map to outer rings. But the library does not enforce any layering scheme.
Blocks are named boundaries. Code lives in exactly one block, imports respect the dependency direction, and each block's public API is explicit about what it offers and what it needs (ports).
Internal Dependency Rules
The library follows these rules internally:
- Foundation depends on nothing.
- Domain depends only on Foundation.
- Application depends on Domain and Foundation.
- Infrastructure depends on Application (for outbound port contracts) and Foundation.
- Presentation depends on Application and Foundation.
These rules maintain clear boundaries within the library itself.
Foundation¶
Responsibility: small, reusable abstractions used throughout the library.
Provides:
Result,Ok,ErrPortand port-related protocols (InboundPort,OutboundPort)Identifiedprotocol for objects carrying an identityMapperprotocol for structured transformationDebuggableprotocol for consistent debug representationsErrorand its structured descendants (validation, rule violation, field, combined) for predictable error handlingFinalMeta,FinalABCMeta, andruntime_finalfor runtime enforcement of method finality
The Foundation block contains abstractions that support the other blocks.
Purpose of Foundation block
The Foundation block provides shared abstractions.
It defines the core building blocks that other blocks depend on.
Foundation abstractions are used by Domain, Application, Infrastructure, and Presentation.
Domain¶
Responsibility: model the problem space — concepts, rules, and invariants.
The Domain block provides:
- Types for meaningful concepts:
Entity,AggregateRoot,ValueObject - Rules and invariants enforced through types and methods
- Domain events for significant occurrences (
Eventbase class)
This block depends only on Foundation and knows nothing about HTTP, SQL, queues, filesystems, or any technical details.
Meaning of Domain
In Psychology, a domain is simply an area of knowledge or activity.
In forging-blocks, the Domain block holds the abstractions for modeling the problem space — concepts and rules that describe what a system is about, not how it is implemented.
Dependency rule
The Domain depends only on Foundation.
It does not depend on Application, Infrastructure, or Presentation, so that domain abstractions remain independent of technical concerns.
Application¶
Responsibility: define workflow contracts and coordination abstractions.
The Application block provides:
- InboundPort abstractions (
UseCase,ApplicationServicePort,MessageHandlerPort) — contracts for operations the system offers - OutboundPort abstractions (
RepositoryPort,MessageBusPort,NotifierPort,UnitOfWorkPort) — contracts for dependencies the system needs - Workflow base classes that define the shape of business operations
The Application block depends on Domain types and defines abstract ports that Infrastructure implements. It contains no technical implementation details.
Dependency rule
Application depends on Domain and Foundation.
It defines both InboundPort and OutboundPort contracts.
Infrastructure implements the OutboundPort contracts (Dependency Inversion Principle).
Infrastructure¶
Responsibility: provide technology-agnostic implementations of outbound port contracts.
The Infrastructure block ships with:
- In-memory repositories (
InMemoryReadRepository,InMemoryWriteRepository) and event stores (InMemoryEventStore) - In-memory messaging (
InMemoryMessageBus,InMemoryEventBus) - Stdlib-based implementations (
OSFileSystem,StdlibLogger) - Unit of Work (
InMemoryUnitOfWork)
These are first-class implementations, not test doubles — they use only the Python standard library and carry no third-party dependencies.
Dependency Rule
Infrastructure depends on Application (for outbound port contracts) and Foundation.
No third-party dependencies are allowed in this library.
Application-specific adapters (SQL databases, message brokers, HTTP clients) belong in consuming projects.
Presentation¶
Responsibility: provide entry-point and interaction abstractions.
The Presentation block provides:
- Adapter patterns for connecting external inputs to Application ports
- Middleware abstractions for cross-cutting concerns
- Error handling utilities for boundary translation
The Presentation block calls the Application block through inbound ports. It stays thin so that behavior remains testable and reusable.