Designing System Architecture Patterns
1. Designing Layered Architecture
| Layer | Responsibility | Example |
| Presentation | UI / API endpoints | REST controllers |
| Application | Use case orchestration | Service classes |
| Domain | Business rules / entities | Domain models |
| Infrastructure | DB, queues, external APIs | Repositories, adapters |
Note: Dependencies flow downward only. Easy to learn but couples layers tightly; risk of anemic domain models.
2. Designing Hexagonal Architecture
| Element | Role |
| Core (domain) | Business logic, no I/O dependencies |
| Ports | Interfaces defined by core (in/out) |
| Adapters | Implementations: REST, JPA, Kafka |
| Driving side | Inbound (HTTP, CLI, tests) |
| Driven side | Outbound (DB, MQ, third-party) |
Example: Hexagonal port/adapter (Java)
// Port (defined in core)
public interface OrderRepository {
Optional<Order> findById(OrderId id);
void save(Order order);
}
// Adapter (infrastructure)
@Repository
class JpaOrderRepository implements OrderRepository {
private final OrderJpaRepo jpa;
public Optional<Order> findById(OrderId id) { return jpa.findById(id.value()).map(this::toDomain); }
public void save(Order order) { jpa.save(toEntity(order)); }
}
3. Designing Clean Architecture
| Ring (inner→outer) | Contents |
| Entities | Enterprise business rules |
| Use Cases | Application-specific business rules |
| Interface Adapters | Controllers, presenters, gateways |
| Frameworks & Drivers | Web, DB, UI, devices |
Note: Dependency rule — source code dependencies point only inward. Inner layers know nothing about outer layers.
4. Designing Onion Architecture
| Ring | Purpose |
| Domain Model | Entities + value objects |
| Domain Services | Cross-aggregate logic |
| Application Services | Orchestration / use cases |
| Infrastructure / UI / Tests | Outer; depend on inner only |
5. Designing Event Sourcing Architecture
| Concept | Description |
| Event Store | Append-only log of state changes |
| Aggregate | Rehydrated by replaying events |
| Snapshot | Periodic state cache to speed replay |
| Projection | Read model built from events |
| Pros | Audit trail, time travel, easy CQRS |
| Cons | Schema evolution, eventual consistency |
Example: Event-sourced aggregate
class Account {
private long balance;
private final List<Event> uncommitted = new ArrayList<>();
void deposit(long amount) {
apply(new MoneyDeposited(amount));
}
void apply(Event e) {
if (e instanceof MoneyDeposited d) balance += d.amount();
uncommitted.add(e);
}
static Account rehydrate(List<Event> history) {
var a = new Account();
history.forEach(a::apply);
a.uncommitted.clear();
return a;
}
}
6. Designing CQRS Architecture
| Side | Optimized For | Storage |
| Command | Writes, validation, business logic | Normalized OLTP, event store |
| Query | Reads, denormalized projections | Read replica, ES, materialized view |
Note: Sync via events. Adds eventual consistency; only adopt when read/write loads diverge significantly.
7. Designing Serverless Architecture
| Component | Service | Use Case |
| Functions | Lambda, Cloud Functions | Event handlers, APIs |
| API Gateway | API GW, Cloud Endpoints | HTTP routing, auth |
| Event Bus | EventBridge, Pub/Sub | Decoupled triggers |
| Storage | DynamoDB, Firestore, S3 | Managed, auto-scaling |
| Limits | Cold start, 15-min timeout, vendor lock | — |
8. Designing Service-Oriented Architecture (SOA)
| Aspect | SOA | Microservices |
| Communication | ESB, SOAP | Lightweight HTTP/gRPC |
| Data | Often shared DBs | DB-per-service |
| Granularity | Coarse | Fine |
| Governance | Centralized | Decentralized |
9. Designing Lambda Architecture
┌──────────────┐
Source ──▶│ Batch Layer │──▶ Batch Views ─┐
│ └──────────────┘ │──▶ Serving Layer ──▶ Query
└──▶ Speed Layer ──▶ Realtime Views ──┘
| Layer | Tech | Trade-off |
| Batch | Spark, Hadoop | Accurate, high latency |
| Speed | Flink, Kafka Streams | Low latency, approximate |
| Serving | Druid, HBase | Merges batch+speed views |
10. Designing Kappa Architecture
| Property | Kappa |
| Layers | Stream-only (no batch) |
| Reprocessing | Replay log from offset 0 |
| Tech | Kafka + Flink/Kafka Streams |
| Pro | Single codebase, simpler than Lambda |
| Con | Requires durable, replayable log |
11. Designing Modular Monolith Architecture
| Aspect | Approach |
| Deployment | Single artifact |
| Modules | Strict package boundaries, no cross-imports |
| Communication | In-process events / interfaces |
| Data | Schema-per-module in shared DB |
| Migration path | Extract module → microservice when needed |
Note: Best starting point for most products — get microservices benefits without distributed system tax.
12. Designing Strangler Fig Pattern
Strangler Migration Steps
- Place a facade/proxy in front of legacy system
- Build new functionality in modern stack behind facade
- Route specific endpoints to new system
- Migrate data incrementally (dual-write or CDC)
- Decommission legacy modules as they are replaced
| Risk | Mitigation |
| Data sync | CDC + reconciliation jobs |
| Stalled migration | Time-box, set kill date for legacy |
| Dual maintenance | Freeze legacy features |