What is Prism Architecture?
Introduction​
Prism Architecture is a modern software architecture pattern designed to address limitations in traditional Domain-Driven Design (DDD), Onion Architecture, and Clean Architecture approaches. It maintains separation of concerns while providing more flexibility, particularly for applications using GraphQL and modern UI frameworks like SwiftUI and Jetpack Compose.
Named "Prism Architecture" to reflect how the architecture separates concerns while allowing domain models to flow through all aspects of the application (similar to how a prism separates light into its component colors), this pattern evolved through practical experience with real-world applications.
Core Philosophy​
The Prism Architecture recognizes that while traditional architectures like DDD and Onion provide valuable separation of concerns, they often create friction in modern application development - particularly when working with GraphQL, state management frameworks, and declarative UI technologies like SwiftUI.
Instead of forcing rigid boundaries that lead to excessive mapping and transformation between layers, Prism Architecture allows for more natural data flow while still maintaining clear responsibilities and separation of concerns. It's designed for developers who value both architectural purity and practical implementation efficiency.
Primary Layer Structure​
Prism Architecture consists of six main layers, each with specific responsibilities:
Core Layer​
- Purpose: Houses stable domain models and core protocols that define the application's fundamental concepts
- Components: Entities, ValueObjects, Enumerations, Core Protocols
- Characteristics: Stable, rarely changing, accessible by all other layers
- Key Concept: Uses strongly-typed identifiers through the ValueObjectID pattern, improving type safety and domain clarity
Domain Layer​
- Purpose: Contains business logic, validation, and domain rules that implement the application's core behavior
- Components: Domain Services, Validation Services, Rule Services, Domain Events
- Characteristics: Focused on business logic, communicates with Orchestration Layer, accesses Core Layer
- Key Concept: Domain Events allow for reactive patterns, enabling complex business processes to be modeled as a series of events and reactions
Orchestration Layer​
- Purpose: Coordinates flow between all other layers, managing application operations
- Components: UseCases, Orchestration Services, Workflow Coordinators, Event Handlers
- Characteristics: Central communicator, mediates between all other layers
- Key Concept: Organized hierarchically from simple entity-focused Use Cases to complex cross-domain Workflows
Infrastructure Layer​
- Purpose: Handles external communication, data access, and system services
- Components: Data Access (GraphQL, REST), System Services, External Services
- Characteristics: Interfaces with external systems, communicates with Orchestration Layer
- Key Concept: GraphQL QueryServices optimize data access for complex queries that may span multiple domain entities
Presentation Layer​
- Purpose: Manages user interface and user interactions
- Components: UI Components, Presenters/ViewModels, Screens, Navigation Controllers
- Characteristics: Flexible internal structure, communicates with Orchestration Layer
- Key Concept: Supports multiple UI patterns including PrismUI, MVVM, TCA, and MVP
Common Layer​
- Purpose: Contains cross-cutting utilities and data transfer objects
- Components: Utilities, Enumerations, DTOs, Display Objects
- Characteristics: Accessible by Infrastructure, Orchestration, and Presentation layers (not Domain)
- Key Concept: DTOs provide a clear separation between domain entities and the data structures used for communication
How Prism Architecture Differs from Traditional Approaches​
Compared to Domain-Driven Design (DDD)​
While DDD isolates entities within bounded contexts and requires explicit translation between contexts, Prism Architecture uses core domain models in a shared Core Layer accessible to all parts of the application. This reduces the need for constant mapping while still maintaining proper domain modeling.
Compared to Onion Architecture​
Unlike Onion Architecture where dependencies only point inward, Prism Architecture makes the Core Layer accessible by all layers, allowing more flexible access patterns. The Orchestration Layer (renamed from Application Layer in Onion) serves as the active coordinator between layers rather than just a boundary.
Compared to Clean Architecture​
Clean Architecture enforces a strict dependency rule where inner layers are unaware of outer layers. Prism Architecture allows the Core Layer to be accessible by all layers, while other communications flow through the Orchestration Layer. Additionally, in Prism, Core Layer entities are primarily data structures, with business logic residing in the Domain Layer.
Key Architectural Patterns​
Bidirectional Event Flow​
- Domain Events originate in the Domain Layer
- Orchestration Layer subscribes to and coordinates responses to Domain Events
- Presentation Layer receives notifications for UI updates
- Infrastructure Layer handles technical aspects of event distribution
Hierarchical Component Organization​
- Use Cases handle simple entity-focused operations
- Orchestration Services manage feature-area operations
- Workflow Coordinators handle complex cross-domain processes
- This creates clear boundaries and responsibilities
State and Intent Handling​
- State flows down the component hierarchy
- User actions flow up as intents or commands
- This creates predictable data flow patterns
- Particularly effective with declarative UI frameworks
GraphQL-Optimized Data Access​
- Repository pattern for standard data access
- Specialized QueryServices for optimized GraphQL queries
- Allows efficient data retrieval across aggregate boundaries
- Maintains domain integrity while optimizing for performance
Key Benefits of Prism Architecture​
-
Reduced Mapping Overhead: With shared domain models accessible to all layers, there's less need for repetitive mapping between similar models.
-
API Flexibility: While designed with GraphQL as a first-class citizen for optimized query performance, the architecture fully supports traditional REST APIs and other communication protocols.
-
UI Framework Compatibility: Designed to work well with modern reactive UI frameworks like SwiftUI and Jetpack Compose.
-
Flexible Yet Structured: Maintains clear separation of concerns while allowing practical flow of data.
-
Layer Autonomy: Each layer has freedom over its internal structure, allowing teams to use appropriate patterns within each area.
-
Natural Testing Boundaries: Clear layer responsibilities create natural boundaries for different testing approaches.
-
Reduced Boilerplate: Less infrastructure code needed to maintain architectural boundaries.
-
Improved Developer Experience: More intuitive for developers to work with, reducing the learning curve while maintaining architectural benefits.
When to Use Prism Architecture​
Prism Architecture is particularly well-suited for:
- Mobile and desktop applications using modern UI frameworks
- Applications using GraphQL for data access
- Projects where developer experience and iteration speed are important
- Teams looking to maintain good architecture without excessive ceremony
- Systems with complex domain models that need to be shared across the application
The Prism Architecture can be effectively used in various contexts, including:
- Enterprise systems of any size, including those with complex domain models
- Organizations seeking to improve development velocity without sacrificing architectural integrity
- New projects where establishing a clean, maintainable architecture from the start is a priority
- Legacy system modernization where improved data flow between components is desired
Traditional DDD, Onion, or Clean Architecture approaches might still be preferred in specific situations:
- Systems where complete domain isolation is an absolute requirement
- Projects where existing investments in these architectural patterns make transition costs prohibitive
- Cases where regulatory requirements mandate strict boundaries between system components