Dua pendekatan arsitektur yang paling diperdebatkan: Monolith (satu aplikasi besar) vs Microservices (banyak service kecil).
Monolith:
┌────────────────────────────┐
│ Satu Aplikasi │
│ ┌──────┐ ┌──────┐ ┌─────┐ │
│ │ Auth │ │Order │ │Email│ │
│ └──────┘ └──────┘ └─────┘ │
│ ┌──────┐ ┌──────┐ ┌─────┐ │
│ │ User │ │ Pay │ │Notif│ │
│ └──────┘ └──────┘ └─────┘ │
│ Satu Database │
└────────────────────────────┘
Microservices:
┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
│ Auth │ │Order │ │ Pay │ │Email │
│ DB │ │ DB │ │ DB │ │ DB │
└──┬───┘ └──┬───┘ └──┬───┘ └──┬───┘
└────────┬┴───────┬─┘ │
API Gateway / Message Queue
Perbandingan:
| Aspek | Monolith | Microservices |
|---|---|---|
| Deploy | Satu deploy | Deploy per service |
| Scaling | Scale seluruh app | Scale per service |
| Codebase | Satu repo | Repo per service |
| Team | Satu team | Team per service |
| Debugging | Mudah (satu proses) | Sulit (distributed) |
| Data | Satu database | Database per service |
| Latency | Function call (nanoseconds) | Network call (milliseconds) |
| Failure | Satu bug = semua mati | Satu service mati ≠ semua mati |
| Complexity | Kode kompleks | Infrastruktur kompleks |
Kapan pakai Monolith:
- Startup tahap awal — kecepatan development lebih penting
- Team kecil (< 10 developer)
- Domain belum jelas — refactor monolith lebih mudah
- MVP dan proof of concept
Kapan pakai Microservices:
- Team besar — banyak team bisa kerja independen
- Scale berbeda per fitur — checkout butuh lebih banyak resource dari profile
- Teknologi berbeda per service — auth pakai Go, ML pakai Python
- Fault isolation penting — satu service down tidak matikan semua
Tantangan microservices:
- Distributed transactions — bagaimana memastikan konsistensi data antar service?
- Service discovery — bagaimana service menemukan satu sama lain?
- Network latency — setiap call antar service ada overhead
- Data consistency — eventual consistency bisa membingungkan
- Monitoring — harus bisa melacak request yang melewati banyak service (distributed tracing)
- Testing — integration testing antar service lebih kompleks
Pola komunikasi antar microservices:
// 1. Synchronous (REST/gRPC) — request langsung
const user = await fetch("http://user-service/api/users/42");
const orders = await fetch("http://order-service/api/users/42/orders");
// 2. Asynchronous (Message Queue) — fire and forget
await queue.publish("order.created", { orderId: 123, userId: 42 });
// Email service dan inventory service subscribe ke event ini
Rekomendasi: Start with Monolith. Mulai dengan monolith yang well-structured (modular monolith), lalu extract ke microservices hanya jika ada kebutuhan nyata. Martin Fowler menyebutnya "Monolith First".
🎭 Analogi sehari-hari: Restoran besar.
- Monolith: 1 dapur besar, semua koki kerja di sana. Order datang, ambil bahan dari kulkas yang sama, masak. Mudah komunikasi tapi sempit, gak bisa scale separate.
- Microservices: dapur sushi, dapur grill, dapur dessert — masing-masing punya bahan sendiri. Kalau dapur grill rame, tambah orang di sana saja. Tapi sekarang ada kepala chef (API gateway) yang koordinasikan order ke dapur yang tepat.
💡 "Monolith First" rule (Martin Fowler): Hampir semua perusahaan unicorn mulai dari monolith. Twitter, Uber, Netflix, Airbnb — semua. Microservices = solusi organizational scaling, bukan technical scaling. Kalau team kamu < 20 orang, monolith lebih cepat ship + lebih mudah debug.
⚠️ Jebakan klasik:
- Premature microservices = team kecil terjebak ops complexity
- Distributed monolith — split jadi services tapi tetap deploy bareng + share DB = worst of both
- Network = source of failure — setiap call lintas service = bisa timeout, retry, race
- Per-service DB tapi cross-service JOIN dibutuhkan = signal split yang salah, redesign domain
- Lupa observability — distributed tracing wajib, gak optional
🎯 Decision tree monolith vs microservices:
- Team ≤ 10 + MVP → Monolith (modular monolith)
- Domain belum jelas → Monolith (refactor lebih mudah dari split-merge)
- Team 10-50 + scale berbeda per fitur → Pisahkan 2-3 service strategis
- Team > 50 + multi-product → Full microservices (DDD bounded contexts)
- Latency mission-critical (HFT, gaming) → Monolith (function call < network call)
TL;DR: Mulai monolith yang well-modulare. Split ke microservices saat ada kebutuhan nyata (team scaling, fault isolation, polyglot tech). Microservices = kompleksitas operasional besar — wajib observability + distributed tracing + idempotent operations.