High-Level Design — Middle¶
Design component interactions: define interfaces, communication patterns, and data contracts. Evaluate trade-offs: synchronous vs. asynchronous, request-response vs. event-driven, tight coupling vs. loose coupling.
The mental model¶
Components interact through interfaces. An interface defines: - What data is exchanged (request/response schema, event format) - How it is exchanged (HTTP, gRPC, message queue, database) - When it happens (synchronous, asynchronous, scheduled) - Failure behavior (what happens if the component is down?)
Tight coupling (direct calls) is simple but fragile. Loose coupling (message queues, events) is resilient but complex.
Communication patterns¶
| Pattern | Example | Pros | Cons |
|---|---|---|---|
| Request-Response | HTTP, gRPC | Simple, immediate feedback | Tight coupling, blocking |
| Publish-Subscribe | Message queue, event bus | Loose coupling, scalable | Eventual consistency, debugging harder |
| Batch Processing | Scheduled jobs | Efficient for large data | Delayed results, complex error handling |
| Streaming | Kafka, Pub/Sub | Real-time, high throughput | Complex state management |
Designing interfaces¶
- Define the contract: What data does the caller send? What does the receiver return?
- Choose the protocol: HTTP for web, gRPC for services, message queue for events.
- Handle errors: What happens if the call fails? Retry? Fallback? Fail fast?
- Version the interface: How do you evolve the interface without breaking callers?
Realistic scenario: E-commerce order processing¶
Components: - Web Server (handles user requests) - Order Service (creates and manages orders) - Payment Service (processes payments) - Inventory Service (tracks stock) - Email Service (sends notifications)
Design decision: Synchronous vs. Asynchronous
Synchronous approach:
Pros: Simple, immediate feedback Cons: If any service is slow or down, the entire flow fails
Asynchronous approach:
User → Web Server → Order Service → Message Queue
↓
Payment Service
↓
Inventory Service
↓
Email Service
Pros: Resilient, scalable Cons: Eventual consistency, harder to debug
Hybrid approach:
Order is created immediately (sync), payment and email happen asynchronously.
Coupling and cohesion¶
Tight coupling: Components depend directly on each other. Changes in one break others.
Loose coupling: Components communicate through well-defined interfaces. Changes are isolated.
High cohesion: Related functionality is grouped together. Unrelated functionality is separated.
Example: - Tight coupling: Order Service directly calls Payment Service's internal database - Loose coupling: Order Service sends a payment request to Payment Service's API
Incremental adoption¶
Start with synchronous request-response. Add asynchronous patterns when you need: - Resilience (services can fail independently) - Scalability (decoupling load) - Eventual consistency (acceptable for some operations)
Verification at multiple levels¶
- Interface level: Can you call the interface and get the expected response?
- Integration level: Do components work together correctly?
- Failure level: What happens when a component is slow or down?
Test yourself¶
- When should you use synchronous vs. asynchronous communication?
- How do you version an interface without breaking callers?
- What is the difference between tight and loose coupling?
- How do you handle failures in a distributed system?
Continue to senior.md.