🧩Key Takeaways
- 1Single Responsibility: each service owns one business capability completely
- 2Database per service: no shared databases — communication only via APIs or events
- 3API-first design: define the contract before implementation, version APIs from day one
- 4Twelve-Factor App: methodology for building cloud-native services (config in env, stateless processes, port binding)
Principles That Actually Matter
Microservices succeed or fail based on how well you define service boundaries. The most common failure mode: splitting services too small (nano-services) or along technical layers instead of business capabilities.
A well-designed microservice is independently deployable, owns its data, and maps to a bounded context from domain-driven design.
Core Principles
Each service should own one complete business capability: Order Service handles everything about orders (CRUD, status, history).
Use DDD bounded contexts: the 'User' in the Auth service is different from 'User' in the Billing service. Each has its own model.
Red flag: if deploying Service A always requires deploying Service B, they should probably be one service.
Each service owns its database — no other service can read or write directly. Data sharing happens through APIs or events.
This is the hardest principle to follow. Cross-service queries feel natural but create tight coupling.
Pattern for cross-service data: API composition (query both services), CQRS (materialized views), or event-driven data replication.
Define the API contract (OpenAPI/protobuf) before writing code. Consumers and producers can develop in parallel.
Version APIs from day one: /v1/orders. Breaking changes = new version. Never break existing consumers.
Use semantic versioning for libraries, URL versioning for REST, package versioning for gRPC.
1. Codebase: One repo per service. 2. Dependencies: Explicitly declare. 3. Config: Environment variables (never hardcode). 4. Backing services: Treat databases as attached resources.
5. Build/release/run: Strict separation. 6. Processes: Stateless, share-nothing. 7. Port binding: Self-contained HTTP server. 8. Concurrency: Scale out via processes.
9. Disposability: Fast startup, graceful shutdown. 10. Dev/prod parity: Keep environments similar. 11. Logs: Write to stdout. 12. Admin processes: Run as one-off tasks.
Advantages
- •Clear boundaries enable team autonomy
- •Independent deployment reduces risk
- •API-first enables parallel development
Disadvantages
- •Database per service complicates cross-service queries
- •Distributed transactions are much harder
- •Requires strong organizational discipline
🧪 Test Your Understanding
What's the 'database per service' principle?