Circuit breakers prevent cascading failures using three states: Closed (normal), Open (blocking requests), Half-Open (testing recovery). Spring Cloud Gateway with Resilience4j (Spring Boot 3+): Configure slidingWindowSize: 10, failureRateThreshold: 50%, waitDurationInOpenState: 5s, permittedNumberOfCallsInHalfOpenState: 3. Implementation: Add resilience4j-spring-boot3 dependency, configure per route with .circuitBreaker() filter. Pattern: After N failures in sliding window, open circuit and return fallback immediately. After wait duration, transition to half-open for limited test requests. Monitor via Spring Boot Actuator /actuator/health endpoint. Benefits: Prevents overwhelming failing services, improves system resilience, provides graceful degradation. 2025 best practice: Combine with rate limiting and retry patterns for complete resilience strategy. Essential for production microservices.
Architectural Patterns 2025 FAQ & Answers
36 expert Architectural Patterns 2025 answers researched from official documentation. Every answer cites authoritative sources you can verify.
unknown
36 questionsService mesh is dedicated infrastructure layer managing service-to-service communication using sidecar proxies. Handles traffic routing, retries, timeouts, encryption, observability, A/B testing. Sidecars deployed alongside each service instance, intercept all network traffic transparently. 2025 leaders: Istio (feature-rich), Linkerd (lightweight). Benefits: (1) Uniform observability - automatic metrics/logs/traces, (2) Language-agnostic - no code changes needed, (3) Security - mTLS between services. Use when: >10 microservices, need cross-cutting networking features, polyglot environment. Trade-off: Adds complexity and latency (~5-10ms). Don't use for <5 services. Essential for large-scale microservices in 2025.
API Gateway manages client-to-service traffic (north-south). Service mesh manages service-to-service traffic (east-west). API Gateway: Single entry point, handles external requests, implements client-facing features (auth, rate limiting, API composition). Service Mesh: Internal communication layer, sidecars on every service, handles inter-service features (retries, circuit breaking, mTLS, observability). Use both together: Gateway for external traffic, mesh for internal. Pattern: Client → API Gateway → Service A (with sidecar) → Service B (with sidecar). 2025 recommendation: API Gateway (Kong, AWS) + Service Mesh (Istio, Linkerd) for complete traffic management. Complementary, not alternatives.
Sidecar proxy deploys alongside application container in same pod, intercepting all network traffic via iptables rules. Application makes normal HTTP/gRPC calls, sidecar captures packets, applies policies (retry, timeout, circuit breaking, mTLS encryption), forwards to destination. Sidecar reports metrics/traces to control plane. 2025 implementations: Istio uses Envoy (0.35 vCPU, 40MB memory per 1000 RPS), Linkerd uses Rust-based linkerd2-proxy (0.8-1.5ms latency, ~10MB memory). Performance: Linkerd 163ms faster than Istio at p99/2000 RPS, 30-40% lower CPU. Benefits: Zero code changes, language-agnostic, automatic observability. Emerging trend: Ambient mesh moves proxies from pods to nodes, reducing overhead. Trade-off: 0.8-10ms latency, resource consumption. Essential for service-to-service security, observability without modifying application code.
Implement defense-in-depth: (1) API Gateway - authentication, authorization, rate limiting at entry point, (2) Service Mesh - mTLS for service-to-service encryption, zero-trust network, (3) Secrets Management - use vault (HashiCorp Vault, AWS Secrets Manager) never hardcode, (4) OAuth 2.0/OIDC - for authentication with JWT tokens, (5) Service Identity - each service has unique identity/credentials, (6) Network Policies - restrict inter-service communication to minimum required. 2025 trend: Zero-trust architecture (verify every request). Tools: Istio for mTLS, Vault for secrets, OAuth/OIDC for auth. Don't: Store credentials in code/env files, trust internal network, skip encryption. Essential for production systems.
Yes, DDD is recommended best practice for microservices design in 2025. DDD provides bounded contexts which map naturally to microservices. Pattern: Each bounded context becomes one microservice (or small group). Benefits: (1) Clear service boundaries - business capabilities not technical layers, (2) Loose coupling - services encapsulate domain logic, (3) Team autonomy - teams own complete domain. Process: Start with domain analysis (identify subdomains), define bounded contexts, model aggregates within context, implement as microservices. Rule: Microservice should be no smaller than aggregate, no larger than bounded context. 2025 consensus: DDD tactical patterns essential for >10 services. Don't use technical boundaries (database, UI) as service boundaries.
CQRS (Command Query Responsibility Segregation) separates read (query) and write (command) operations into different models. Command side orders system to update state. Query side retrieves information without changing state. Benefits: (1) Independent scaling - optimize reads/writes separately, (2) Simplified queries - denormalized read models, (3) Performance - read replicas without write contention. Use when: High read/write ratio differences, complex domain logic, need event sourcing, performance critical. Don't use: Simple CRUD apps, low traffic, team unfamiliar with pattern. 2025 implementation: NestJS CQRS module, MediatR (.NET). Pattern often combined with Event Sourcing. Essential for high-scale systems with different read/write requirements.
Event Sourcing stores all changes as sequence of immutable events instead of current state. Events are facts that happened (OrderPlaced, PaymentReceived). Current state reconstructed by replaying events. Benefits: (1) Complete audit trail - know why/when every change occurred, (2) Time travel - rebuild state at any point, (3) Event-driven - publish events to trigger other processes, (4) Debugging - replay events to reproduce bugs. Implementation: Store events in append-only log (EventStoreDB, Kafka), use snapshots for performance (rebuild from snapshot + recent events). Use when: Need audit trail, complex domain, temporal queries. Trade-off: Complexity, eventual consistency. 2025 tools: EventStoreDB, Kafka, Axon Framework. Essential for regulated industries, complex domains.
EventStoreDB is purpose-built for Event Sourcing. Implementation: (1) Install @eventstore/db-client, create global module in NestJS, (2) Define immutable events as TypeScript classes, (3) Append to streams: client.appendToStream(streamName, jsonEvent({type, data})), (4) Rebuild state via client.readStream(streamName). Modern pattern: Use Decider pattern with initialState, evolve (apply event), decide (command → events) functions for command handlers. Event handlers process events and persist via appendToStream. Materialized views: Use projections or view updaters to update read database from event stream. 2025 best practice: EventStoreDB for write model (source of truth), PostgreSQL/MongoDB for read models (CQRS). Snapshots every 100 events for performance. Unlike frameworks like Axon, requires hands-on approach. Essential for audit trails, temporal queries, complex domains.
Yes, but not ideal alone. Kafka provides append-only log, durable retention, high throughput. Limitations: (1) No optimistic concurrency - EventStoreDB provides ExpectedVersion for safe concurrent writes, Kafka requires additional work, (2) Stream vs entity loading - Kafka optimized for topic streams, not loading specific entity by ID, (3) Ordering only per partition - need partition per aggregate (doesn't scale) or single partition topic, (4) Limited queryability - can't query by event type without additional tooling, (5) No built-in snapshots/projections. 2025 hybrid approach: EventStoreDB stores events as source of truth, projections create meaningful events, Kafka distributes to downstream systems/analytics. Pattern: Write to EventStoreDB → publish to Kafka via Kafka Connect. Use pure Kafka only if throughput > transactional guarantees. Kafka excels at event distribution, EventStoreDB purpose-built for event storage.
Use @nestjs/cqrs package (lightweight CQRS module). Pattern: (1) Define Commands (write) and Queries (read) as classes, (2) Create @CommandHandler and @QueryHandler decorated classes implementing ICommandHandler/IQueryHandler, (3) Inject CommandBus/QueryBus, dispatch via commandBus.execute(command) or queryBus.execute(query). Commands modify state, publish events via EventBus. Queries return data without side effects. Flow: Command → CommandHandler → Domain logic → Events → EventBus → EventHandlers. Query → QueryHandler → Read repository. Event publishing: Use apply() method in aggregate, then commit() to dispatch. External event bus integration possible via custom EventBus implementation. @nestjs/cqrs is lightweight - doesn't include event persistence, add via EventStoreDB/PostgreSQL/MongoDB. Benefits: Separation of concerns, independent read/write scaling, improved auditability. Essential for complex domains requiring different read/write models.
Event Store (EventStoreDB, relational DB): Permanent storage of domain events, append-only, queryable by aggregate/stream, supports projections, optimistic concurrency control. Primary use: Event Sourcing, audit trail, state reconstruction. Message Broker (Kafka, RabbitMQ): Transient message passing between services, pub/sub patterns, routing/filtering, high throughput. Primary use: Asynchronous communication, event distribution, decoupling services. Key difference: Event store is source of truth (persistent), broker is transport mechanism (may be transient). 2025 pattern: Use both together - EventStoreDB for event persistence, Kafka for publishing events to consumers. Don't use Kafka alone for Event Sourcing (limited queryability, retention issues). Use event store + broker for production systems.
Tactical DDD patterns structure domain model within single bounded context with precision. Core patterns: (1) Entities - objects with unique identity persisting over time (User, Order), (2) Value Objects - immutable objects defined by attributes (Money, Address), (3) Aggregates - consistency boundary around entities/value objects, (4) Repositories - abstract data access for aggregates, (5) Domain Services - stateless operations not belonging to entity, (6) Domain Events - significant occurrences in domain. Purpose: Model transactional invariants, ensure consistency, capture domain complexity. Apply within bounded context after strategic design (identifying contexts). 2025 usage: Essential for microservices >10 services. Aggregates define transaction boundaries. Tools: TypeScript classes, decorators for DDD primitives. Don't apply to simple CRUD - overhead not worth it.
Aggregate is cluster of entities and value objects treated as single unit for data changes. Defines consistency boundary and transactional boundary. Contains Aggregate Root (single entity as entry point) plus internal entities/value objects. Rules: (1) External objects reference aggregate by root ID only, (2) Root enforces invariants across entire aggregate, (3) Transactions don't span multiple aggregates, (4) Aggregates should be small (8-10 domain concepts maximum). Purpose: Model transactional invariants, ensure consistency. Example: Order (root) contains OrderLines (entities) and Address (value object). 2025 best practice: Keep aggregates small for performance, use domain events for cross-aggregate consistency. In microservices, aggregate often maps to API endpoint. Essential boundary concept for DDD.
Bounded Context defines specific boundary where domain model is consistent and valid. Within context, terms have precise meaning (e.g., 'Customer' in Sales vs Shipping contexts). Ensures separation of concerns, reduces coupling. Each context has own ubiquitous language, models, database schema. Contexts integrate via well-defined contracts (APIs, events). In microservices: Bounded context typically maps to microservice (one-to-one ideal). Rule: Microservice should be no smaller than aggregate, no larger than bounded context. Example: E-commerce has contexts: Catalog, Ordering, Shipping, Payment. 2025 pattern: Start with domain analysis, identify subdomains, define bounded contexts, implement as microservices. Essential for maintaining model integrity in large systems. Don't let contexts overlap.
Entities have unique identity persisting over time. Identity matters more than attributes. Two entities with same attributes but different IDs are different. Example: User(id=1, name='John') ≠ User(id=2, name='John'). Mutable - can change attributes while keeping identity. Value Objects are immutable, defined entirely by attributes. No unique identity. Two value objects with same attributes are equal. Example: Money(amount=100, currency='USD') = Money(amount=100, currency='USD'). Cheap to create/discard. 2025 implementation: Entities as classes with ID field, Value Objects as immutable classes with equality based on all fields. TypeScript: Use readonly properties for value objects. Use value objects liberally - reduces complexity, enables caching, simplifies testing.
One bounded context typically maps to one microservice (ideal one-to-one mapping). Context defines business capability boundary, microservice implements it. Microsoft Azure architecture principle: Microservice should be no smaller than aggregate, no larger than bounded context. Each service self-contained, implements single business capability within context, owns data/schema. Benefits: Clear boundaries, loose coupling, team autonomy, independent evolution. Communication patterns: (1) REST APIs (synchronous requests), (2) Domain events (asynchronous integration), (3) Anti-corruption layer (legacy integration). Don't: Split context across services (breaks consistency), combine multiple contexts in one service (tight coupling). 2025 strategic DDD approach: Define large-scale structure using bounded contexts, use tactical DDD for internal microservice design. Best practice: Start with modular monolith organized by contexts, extract to microservices when scaling/autonomy needed. Context boundaries = natural service boundaries.
Keep aggregates small and focused - smaller is better for performance and concurrency. Rule: Include only entities/value objects requiring atomic consistency. If entities can change independently, make separate aggregates. Performance trade-off: Larger aggregates = simplicity but worse concurrency. Larger size = increased transaction time, more locking, higher resource consumption. 2025 guideline: Single aggregate root + 2-5 internal entities common. Maximum 8-10 domain concepts. Lazy loading trap: If tempted to leave data unloaded, aggregate boundaries likely wrong - redesign. Model aggregates according to use cases. Use domain events for cross-aggregate consistency (eventual consistency acceptable). Example: Order (root) + OrderLines (entities) in one aggregate. Customer separate aggregate, referenced by ID only. Don't include everything related - only transactional invariants. For reads/queries: Lazy loading acceptable, or use CQRS to avoid loading aggregate. Prefer multiple small aggregates.
EDA is architectural pattern where services communicate via asynchronous events. Producers emit events when state changes. Consumers subscribe to events and react. Events are immutable facts (OrderPlaced, PaymentReceived). Benefits: (1) Loose coupling - producers don't know consumers, (2) Scalability - async processing handles spikes, (3) Resilience - consumers process at own pace. Core components: Message brokers (Kafka, RabbitMQ, AWS EventBridge), event producers, event consumers. 2025 adoption: Essential for IoT (billions of events), 5G low-latency applications, microservices (>10 services). Patterns: Pub/Sub, Event Sourcing, CQRS, Saga. Trade-offs: Eventual consistency, debugging complexity. Use when: Loose coupling needed, high throughput, async workflows. Don't use: Simple request/response, need immediate consistency.
Saga manages distributed transactions across microservices without two-phase commit. Breaks long transaction into sequence of local transactions, each with compensating transaction for rollback. If step fails, execute compensating transactions in reverse order to undo changes. Example: OrderSaga: ReserveInventory → ProcessPayment → ShipOrder. If payment fails: Release inventory (compensating). Two implementations: Choreography (services react to events) and Orchestration (central coordinator). 2025 adoption: 78% of microservices >10 services use Saga (CNCF 2024). Essential for maintaining consistency across services without distributed locks. Use when: Multi-step business process, cross-service transactions, need reliability. Tools: Temporal, Camunda, custom with Kafka/Celery.
Choreography: Services react to events emitted by other services. No central controller. Each service knows what event to listen for and what event to emit next. Decentralized decision-making. Example: OrderService emits OrderPlaced → PaymentService listens, processes, emits PaymentReceived → ShipmentService listens, ships. Orchestration: Central coordinator (Saga orchestrator) tells each service what to do and when. Centralized control flow. Orchestrator tracks state, handles failures, triggers compensating transactions. Example: OrderSaga orchestrator calls PaymentService, then ShipmentService. 2025 guideline: Use choreography for simple flows (<5 steps), orchestration for complex workflows (>5 steps, conditional logic). Choreography = loose coupling but harder to track. Orchestration = easier debugging but single point of failure.
Use Choreography when: (1) Simple linear workflow (<5 steps), (2) High service autonomy desired - fully decoupled, (3) No complex conditionals/branching, (4) Team prefers event-driven. Benefits: Loose coupling, no single point of failure. Challenges: Difficult global timeouts/retries/resiliency (must implement per component), harder end-to-end monitoring. Use Orchestration when: (1) Complex workflow (>5 steps, conditionals, loops), (2) Centralized visibility/monitoring needed, (3) Complex compensation logic, (4) Frequent business process changes. Benefits: Centralized control, easier debugging/traceability, clear error handling, explicit workflow logic. Challenges: Orchestrator can be single point of failure. 2025 tools: Choreography (Kafka, EventBridge), Orchestration (Temporal - code-based workflows with guaranteed progress, AWS Step Functions, Camunda). Temporal advantage: Logic in code vs JSON/graphs, no lost progress. Recommendation: Start choreography for simple flows, migrate to orchestration as complexity grows. Don't mix in same saga.
Top choices: (1) Apache Kafka - high-throughput streaming (millions msg/sec), event sourcing, durable retention, distributed. Use for: Event logs, real-time analytics, >100k msg/sec. (2) RabbitMQ - flexible routing, strong delivery guarantees, mature. Use for: Complex routing, RPC patterns, <50k msg/sec. (3) Cloud-native: AWS EventBridge (serverless, AWS integrations), Google Pub/Sub (auto-scaling, global), Azure Service Bus (enterprise features). 2025 trends: Kafka dominant for event streaming, RabbitMQ for traditional messaging, cloud services for managed simplicity. Choose Kafka if: Need stream processing, event sourcing, high scale. Choose RabbitMQ if: Need flexible routing, priority queues, lower scale. Choose cloud if: Want managed service, tight cloud integration.
Compensating transaction semantically reverses effects of successful local transaction when saga fails. Pattern: Execute forward steps sequentially. On failure, execute compensating transactions in reverse order (last to first). Example: ReserveInventory (step) → ReleaseInventory (compensation). Critical requirements: (1) Idempotent - safe to retry without side effects, (2) Retryable - must eventually succeed, can't fail permanently, (3) Semantic reversal - doesn't restore exact state, reverses business effect. Implementation: Store saga state (completed steps) in database. On failure, trigger compensations from completed steps in reverse. Azure pattern: Define compensating steps as idempotent commands. Handle transient failures effectively. Design compensations before implementing saga. 2025 best practice for AWS Lambda: Ensure compensating functions idempotent to prevent duplicate effects. Hard-to-compensate operations (emails): Use reservation/hold patterns. Essential for maintaining consistency across distributed transactions without 2PC.
Hexagonal Architecture (Ports and Adapters) isolates core business logic from external dependencies. Core (domain logic) in center, ports (interfaces) define boundaries, adapters (implementations) connect to external systems (databases, APIs, UI). Benefits: (1) Framework independence - swap frameworks without changing core, (2) Testability - test business logic without external dependencies, (3) Flexibility - multiple adapters for same port (e.g., PostgreSQL vs MongoDB). Structure: Application Service (use cases) → Port (interface) → Adapter (implementation). Driving side: User → Adapter (REST controller) → Port → Core. Driven side: Core → Port → Adapter (database repository). 2025 usage: TypeScript/NestJS implementations popular. Essential for long-lived applications needing flexibility.
Ports are interfaces defining contracts between core business logic and external world. Technology-agnostic boundaries. Two types: (1) Driving ports (primary/inbound) - API application offers to external actors, initiated by outside (IOrderService with createOrder), Application Service implements this interface, (2) Driven ports (secondary/outbound) - dependencies core needs from external systems (IOrderRepository with save), Adapters implement this interface, Application depends on port. On driving side: Adapter depends on Port, Application implements Port. On driven side: Application depends on Port, Adapter implements Port. Example: INotificationService port, EmailAdapter and SMSAdapter both implement it. Benefits: Dependency Inversion Principle - core depends on abstractions not concretions, swap implementations without changing core. 2025 TypeScript: Define ports as interfaces in domain layer, inject concrete adapters via DI. Port names reflect domain language (IOrderRepository) not technology (IPostgreSQLStorage).
Adapters are concrete implementations connecting core business logic to external systems via ports (interfaces). Contain technology-specific logic. Two types: (1) Driving adapters (primary) - receive requests from external actors, call core through driving ports (REST controllers, GraphQL resolvers, CLI, WebSocket handlers, message consumers), (2) Driven adapters (secondary) - called by core to access external resources through driven ports (database repositories, HTTP clients, email services, file systems). Dependency direction: Driving adapters depend on core, core depends on driven port abstractions (not adapters themselves). Example: PostgreSQLOrderRepository (driven adapter) implements IOrderRepository (driven port), contains SQL queries. Benefits: Swap implementations without changing core (PostgreSQL → MongoDB = change adapter only). 2025 NestJS pattern: Adapters as infrastructure-specific providers, use DI container to wire to ports. Adapters contain non-functional requirements (infrastructure), core contains functional requirements (business logic).
Structure: (1) Domain layer - entities, value objects, domain services (pure TypeScript, zero framework dependencies), (2) Application layer - use cases, ports as TypeScript interfaces (IOrderRepository, INotificationService), (3) Infrastructure layer - adapters implementing ports (PostgreSQLOrderRepository, EmailNotificationService). NestJS ideal fit: Modular architecture aligns with separation of concerns, built-in DI manages dependencies. Implementation: Define port interface in application (export interface IOrderRepository), implement adapter in infrastructure (class PostgreSQLOrderRepository implements IOrderRepository), inject via constructor with @Injectable. Example: class CreateOrderUseCase { constructor(private repo: IOrderRepository) {} execute() { this.repo.save(order); }}. Domain triggers events, infrastructure adapter publishes (event-driven integration). 2025 pattern: Organize by feature folders (orders/domain, orders/application, orders/infrastructure). Domain never depends on technology - no DB, HTTP, NestJS - just TypeScript classes/interfaces. Essential for testable, maintainable, long-lived applications.
Dependency Injection wires adapters to ports at runtime, enabling Dependency Inversion Principle. Core depends on port abstractions, DI container injects concrete adapters. Pattern: Application defines output port interface, adapter implements interface, DI injects desired implementation at runtime. NestJS built-in DI makes this natural: Use @Injectable on adapter, constructor injection in use cases. Example: class CreateOrderUseCase { constructor(@Inject('IOrderRepository') private repo: IOrderRepository) {} }. Module registration: { provide: 'IOrderRepository', useClass: PostgreSQLOrderRepository }. Benefits: (1) Testing - inject mock adapters for unit tests, (2) Flexibility - swap implementations via configuration without code changes, (3) Loose coupling - core unaware of concrete technologies. NestJS contracts satisfied at runtime via DI. 2025 tools: NestJS DI (most popular for TypeScript), InversifyJS, TSyringe. Domain never imports infrastructure, infrastructure imports domain. Essential for achieving true decoupling in Hexagonal Architecture.
Clean Architecture organizes code into concentric layers with dependencies pointing inward. Created by Robert C. Martin (Uncle Bob). Goal: Framework independence, testability, UI independence, database independence. Core principle: Dependency Rule - source code dependencies only point inward, inner layers know nothing about outer layers. Layers: (1) Entities (innermost - enterprise business rules), (2) Use Cases (application business rules), (3) Interface Adapters (controllers, presenters, gateways), (4) Frameworks & Drivers (outermost - UI, database, web). Benefits: Business logic isolated, easy to test, swap frameworks/databases without changing core. 2025 adoption: Popular for enterprise applications, microservices, domain-heavy systems. Similar to Hexagonal Architecture with explicit layer structure. Essential for long-term maintainability.
Four concentric layers from inside out: (1) Entities - enterprise business rules, most stable, least likely to change, plain objects with no framework dependencies (User, Order domain models), (2) Use Cases - application-specific business rules, orchestrate entities, implement business flows (CreateOrderUseCase, ProcessPaymentUseCase), (3) Interface Adapters - convert data between use cases and external world (REST controllers, database repositories, presenters), (4) Frameworks & Drivers - tools and frameworks (web framework, database, UI, external APIs). Dependency Rule: Each layer only depends on layers inside it, never outside. 2025 implementation: Entities/Use Cases in TypeScript, Interface Adapters as NestJS controllers/repositories, Frameworks as Express/PostgreSQL/React. Inner layers define interfaces, outer layers implement them.
Dependency Rule: Source code dependencies can only point inward toward higher-level policies. Nothing in inner circle knows anything about outer circle. Outer layers depend on inner, never reverse. Entities don't know about Use Cases. Use Cases don't know about Controllers. Controllers know about Use Cases. Benefits: Core business logic isolated from external concerns, easy to test inner layers without UI/database, swap outer layers (frameworks, databases) without changing inner layers. Implementation: Inner layers define interfaces (ports), outer layers implement them (adapters). Use Dependency Injection to pass implementations at runtime. Example: Use Case defines IOrderRepository interface, outer layer implements PostgreSQLOrderRepository. 2025 enforcement: Use linters (ESLint with import restrictions) to prevent upward dependencies. Critical rule for Clean Architecture.
Entities encapsulate enterprise-wide business rules (innermost layer). Most general, high-level concepts. Independent of any application - could be used across multiple systems. Zero framework dependencies, no database awareness. Plain objects with methods embodying critical business rules. Least likely to change when external factors (UI, database, frameworks) change. Heart of Clean Architecture - enterprise business rules. Examples: User entity with validation rules, Order entity with price calculation logic, Account entity with balance management. Strict rules: (1) No dependencies on outer layers, (2) No framework imports, (3) Pure business logic only, (4) Framework-agnostic. 2025 TypeScript implementation: Classes with business methods, immutable properties preferred, domain invariants enforced in constructors/methods. Not just data holders (DTOs) - contain behavior and business logic. Use cases orchestrate entities, but entities contain the fundamental rules. Essential for isolating enterprise business rules from application-specific concerns.
Use Cases contain application-specific business rules (second layer from inside). Orchestrate flow between entities and external interfaces. Direct entities to use enterprise rules to achieve application goals. Each use case represents single application operation (CreateOrder, ProcessPayment, CancelSubscription). Define what app can do. Structure: Input (DTO/request model - plain data), Processing (orchestrate entities), Output (DTO/response model). Use cases define interfaces for dependencies (IRepository, IGateway), outer layers implement. Know about repositories and use them, but repositories don't know about use cases (Dependency Inversion). 2025 TypeScript pattern: One class per use case implementing IUseCase interface. Constructor accepts validators, DAOs, utilities via DI. Execute/handle method contains workflow. Example: CreateOrderUseCase receives DTO, validates, creates Order entity, saves via IOrderRepository. Pure business logic layer - zero framework code. Benefits: Testable without UI/database, clear operations, delivery-mechanism independent. Domain never depends on technology.
Framework independence means core business logic (Entities, Use Cases) has zero dependencies on frameworks (Express, NestJS, React, Angular). Frameworks are tools in outermost layer, easily replaced. Business rules don't know if they're served via REST, GraphQL, CLI, or message queue. Benefits: (1) Framework changes don't affect business logic, (2) Business logic testable without framework, (3) Migrate to new framework without rewriting core, (4) Business logic portable across applications. Pattern: Core defines interfaces for external concerns, framework layer implements them. Example: Use case defines INotificationService, framework provides EmailNotificationService (SendGrid) or SMSNotificationService (Twilio). 2025 reality: Frameworks change every 3-5 years, business logic lasts 10+ years. Protect business logic from framework churn. Essential for long-term maintainability.
Both isolate business logic from external concerns via Dependency Inversion Principle. At core, same pattern: DIP-based, dependencies run outside-to-inside. Key differences: (1) Structure - Clean uses four explicit layers (Entities, Use Cases, Interface Adapters, Frameworks) with concentric circles, Hexagonal uses two-sided model (driving/driven ports) with less prescriptive internal structure. (2) Terminology - Clean uses specific layer names (domain, application), Hexagonal uses generic terms (ports, adapters). (3) Dependency hierarchy - Clean prescribes strict layer hierarchy, Hexagonal allows flexibility with dependency direction. (4) Granularity - Clean fixes layer count, Hexagonal allows multiple hexagons as needed. (5) Focus - Clean emphasizes internal application structure, Hexagonal emphasizes external integration boundaries. Historical: Hexagonal came first, Clean filled implementation gaps. Similarities: Dependency Inversion, framework independence, testability. 2025 guidance: Choose Clean for structured teams preferring explicit layers, Hexagonal for flexibility and clear external boundaries. Principles matter more than names. Can combine both.