DDD untuk Microservices
Domain-Driven Design membantu menentukan batas microservice yang benar. Tanpa DDD, service boundaries seringkali arbitrary dan menghasilkan distributed monolith.
Bounded Context
Setiap bounded context = satu microservice (idealnya). Model yang sama bisa punya arti berbeda di context berbeda.
// "User" di Auth Context
{ id, email, passwordHash, lastLogin }
// "User" di Order Context
{ id, name, shippingAddress, paymentMethod }
// "User" di Notification Context
{ id, email, notificationPreferences }
// Beda context, beda model — TIDAK share database!
Aggregate
Cluster of entities yang diperlakukan sebagai satu unit. Aggregate root menjaga consistency.
// Order aggregate
class Order {
id: string;
items: OrderItem[]; // part of aggregate
status: OrderStatus;
addItem(product, qty) {
// Business rule: max 50 items per order
if (this.items.length >= 50) throw new Error("Max items reached");
this.items.push(new OrderItem(product, qty));
}
submit() {
if (this.items.length === 0) throw new Error("Empty order");
this.status = "submitted";
// Emit domain event
this.addEvent(new OrderSubmittedEvent(this.id));
}
}
Context Map
- Shared Kernel — Dua context share sebagian model (hati-hati coupling)
- Customer-Supplier — Satu context bergantung pada output context lain
- Anti-Corruption Layer — Translate model dari external context ke internal model
- Published Language — Shared API contract (OpenAPI, protobuf)
Strategic vs Tactical DDD
- Strategic (paling penting) — Bounded contexts, context maps, ubiquitous language
- Tactical (opsional) — Entities, value objects, aggregates, repositories, domain events
🎭 Analogi sehari-hari
Restoran besar punya banyak departemen: dapur (cooking), kasir (billing), gudang (inventory), HR (staff). Setiap departemen punya istilah sendiri untuk hal yang sama: "ayam" di dapur = "stock SKU-1234" di gudang = "Rp 75.000" di kasir. Semua valid di context masing-masing. Kalau dipaksa satu model untuk semua = chaos. DDD bilang: biarkan setiap bounded context punya bahasa & model sendiri.
💡 DDD tanpa Microservices?
Ya, bisa! DDD adalah strategi modeling, bukan arsitektur. Modular monolith dengan bounded contexts yang jelas = bagus. Microservices tanpa DDD = distributed monolith (boundary salah). Urutan: DDD dulu, microservices kalau perlu, bukan sebaliknya.
⚠️ Jebakan klasik
- Shared database antar bounded context = boundary palsu, perubahan satu service break yang lain
- "User" jadi god model di semua context — kasih beda nama:
AuthUser,OrderCustomer,NotificationRecipient - Anemic domain model = entity cuma getter/setter, semua logic di service. DDD inti: logic di domain object
- Tactical DDD tanpa Strategic = ribet pakai value object, repository, dll tapi boundary salah = useless
- Ubiquitous language tidak konsisten = "order" di code, "transaksi" di docs, "pesanan" di UI = miscommunication
🎯 DDD adoption order
- Event Storming dengan domain expert — kumpulin event domain di whiteboard
- Identify bounded contexts — kelompokin event yang related
- Ubiquitous language — kasih nama konsisten di code + docs + UI per context
- Aggregate roots per context — entity yang jaga consistency
- Context map — gambar relasi antar context (anti-corruption layer di mana)
- Implement — modular monolith dulu, microservices kalau organizational scaling butuh
TL;DR: DDD = modeling strategy untuk complex domain. Bounded context = batas model + bahasa. Wajib sebelum microservices (kalau gak, boundary salah). Strategic DDD (context, language) > Tactical DDD (aggregate, value object). Modular monolith dengan DDD = sweet spot untuk most apps.