Data mesh membagi data per domain, tetapi menimbulkan pertanyaan penentu: batas domain ditentukan dari mana? Memotong mengikuti struktur tim bisa salah ketika tim direorganisasi; memotong mengikuti sistem yang kebetulan ada bisa mencampur konsep yang berbeda. Domain-driven design (DDD), yang dirintis Eric Evans di dunia rekayasa perangkat lunak, menyediakan kosakata yang teruji untuk masalah ini: bounded context, ubiquitous language, agregat, dan anti-corruption layer. Bab ini menerjemahkan kosakata tersebut ke dunia arsitektur data dan membuktikan manfaatnya lewat simulasi.

Bounded Context dan Bahasa Domain #

Inti DDD adalah pengakuan bahwa satu kata bisa berarti hal berbeda di bagian organisasi yang berbeda. Kata “pesanan” di domain Pesanan berarti keranjang belanja beserta status pembayarannya; di domain Pengiriman, “pesanan” berarti paket fisik dengan alamat dan nomor resi. Bounded context adalah batas validitas sebuah model: di dalam batas tersebut, satu istilah punya satu makna yang disepakati — inilah yang disebut ubiquitous language.

Istilah DDDMaknaPadanan arsitektur data
Bounded Contextbatas validitas sebuah modeldomain data dengan schema miliknya
Agregatkumpulan objek yang konsisten bersamatabel atau entity inti domain
Ubiquitous Languagekosakata bersama satu timnama kolom dan metrik yang konsisten
Anti-Corruption Layerpenerjemah antar modelmapping schema di pipeline

Setiap bounded context menerbitkan datanya sebagai data product — titik di mana DDD bertemu mesh dan fabric dari dua chapter sebelumnya:

Anti-Corruption Layer #

Ketika konteks Analitik memakai data dari konteks Pesanan, Analitik tidak boleh menempel pada schema milik Pesanan. Bila menempel, perubahan kecil di sumber — ganti nama kolom, ubah format — langsung merembet ke semua konsumen. Anti-corruption layer (ACL) memutus rembetan tersebut: sebuah lapisan penerjemah yang dimiliki konsumen, mengubah event sumber menjadi bentuk internal konsumen. Sumber bebas berevolusi; selama ACL diperbarui, konsumen tidak merasakan apa-apa.

Simulasi ACL dengan Python #

Kita simulasikan penerjemahan event antar konteks TokoKita. Domain Pesanan mengirim event dengan schema miliknya; konteks Analitik memiliki peta terjemahan dan atribut internalnya sendiri:

python
# Event dari domain Pesanan - schema dimiliki domain Pesanan
event_pesanan = {
    "order_id": "ORD-0042",
    "pelanggan": "budi",
    "nilai_idr": 128000,
    "terjadi_pada": "2026-01-15T09:12:00+07:00",
    "sumber": "app-android",
}

# Konteks Analitik tidak mengenal nama kolom milik domain Pesanan;
# ACL memegang peta terjemahan dan atribut internal milik Analitik.
PETA_KOLOM = {
    "order_id": "order_key",
    "nilai_idr": "gross_idr",
    "terjadi_pada": "event_ts",
}
ID_PELANGGAN = {"budi": "C-1001", "siti": "C-1002", "dewi": "C-1003"}


def terjemahkan(event):
    """ACL: ganti nama kolom, isi customer_id, buang kolom asing."""
    hasil = {}
    for kolom, nilai in event.items():
        if kolom in PETA_KOLOM:
            hasil[PETA_KOLOM[kolom]] = nilai
    hasil["customer_id"] = ID_PELANGGAN.get(event["pelanggan"], "C-TAKDIKENAL")
    hasil["context"] = "analitik"
    return {k: hasil[k] for k in sorted(hasil)}

Baris pencetakan event masuk dan keluar dipangkas dari tampilan; hasil eksekusi skrip lengkap berikut:

Output yang Dihasilkan:

text
Event masuk - schema domain Pesanan:
  order_id     ORD-0042
  pelanggan    budi
  nilai_idr    128000
  terjadi_pada 2026-01-15T09:12:00+07:00
  sumber       app-android
Event keluar - schema konteks Analitik, hasil ACL:
  context      analitik
  customer_id  C-1001
  event_ts     2026-01-15T09:12:00+07:00
  gross_idr    128000
  order_key    ORD-0042
Kolom 'pelanggan' dan 'sumber' tidak pernah sampai ke Analitik.
Setelah ganti nama kolom di sumber, output Analitik tetap sama: True

Mari kita telaah baris-baris kode di atas:

  1. Blok pertama, baris 12-16 (PETA_KOLOM): peta terjemahan dimiliki konteks Analitik, bukan domain Pesanan — konsumen yang menentukan bentuk datanya sendiri.
  2. Blok pertama, baris 17 (ID_PELANGGAN): registry identitas internal Analitik; nama pengguna dari sumber diterjemahkan menjadi customer_id yang stabil.
  3. Blok pertama, baris 20-28 (terjemahkan): hanya kolom yang terdaftar di peta yang diteruskan — pelanggan dan sumber dibuang, terbukti pada baris output “Kolom ‘pelanggan’ dan ‘sumber’ tidak pernah sampai ke Analitik”.
  4. Baris output terakhir (True): verifikasi bahwa perubahan di sumber tidak mengubah hasil konsumen — uji ini dijalankan blok kedua berikut.

Perubahan di Sumber Tanpa Guncangan #

Ujian sesungguhnya sebuah ACL adalah ketika sumber berubah. Domain Pesanan mengganti nama kolom order_id menjadi order_ref; ACL cukup menambah satu baris pemetaan:

python
# Domain Pesanan mengganti nama kolom 'order_id' menjadi 'order_ref';
# ACL diperbarui, konsumen Analitik tidak merasakan apa pun.
event_baru = dict(event_pesanan)
del event_baru["order_id"]
event_baru["order_ref"] = event_pesanan["order_id"]
PETA_KOLOM["order_ref"] = "order_key"
hasil_baru = terjemahkan(event_baru)
print("Setelah ganti nama kolom di sumber, output Analitik tetap sama:",
      hasil_baru == hasil_acl)

Blok tersebut membangun event versi baru, memperbarui peta pada satu baris (PETA_KOLOM["order_ref"] = "order_key"), lalu memverifikasi hasil terjemahan tetap identik — baris True di akhir output. Tanpa ACL, perubahan nama kolom semacam ini akan memaksa setiap konsumen mengubah query-nya di saat yang sama.

Penjelasan klasik pola ACL dalam rekayasa perangkat lunak ditulis Martin Fowler di bliki AntiCorruptionLayer , sedangkan penerapan data-nya beririsan dengan Schema Registry dan Data Contracts dari section sebelumnya.

Dengan domain, kontrak, dan penerjemah di tempatnya, kita telah menata sisi organisasi dan sisi data. Pertanyaan berikutnya kembali ke mesin: bagaimana batch dan streaming hidup berdampingan di atas fondasi yang sama? Chapter Batch dan Streaming Architecture merangkainya.