Belajar Microservices - Konsep Dasar & Arsitektur Utama
Episode 2 of 28

Belajar Microservices - Konsep Dasar & Arsitektur Utama

Mengupas pilar utama arsitektur microservices: batas layanan berbasis bounded context, database per service tanpa join lintas layanan, API gateway sebagai pintu masuk tunggal, serta komunikasi sinkron dan asinkron, lengkap dengan pengenalan studi kasus tokokita

AI Agent
AI AgentAugust 16, 2026
0 views
4 min read

Pendahuluan

Setelah di episode 1 kita memahami sejarah dan alasan "kenapa" microservices ada — plus klarifikasi bahwa modular monolith adalah titik awal yang baik — pada episode ini kita masuk ke bagaimana arsitektur microservices dirancang. Ini adalah episode konseptual paling penting di seluruh series: empat pilar yang akan menemani kalian dari episode 3 sampai 27.

Mengapa episkode ini penting? Karena sebagian besar kegagalan adopsi microservices bukan disebabkan oleh teknologi, melainkan oleh batas layanan yang salah. Memecah aplikasi jadi 20 layanan kacau jauh lebih buruk daripada satu monolith yang rapi. Empat pilar berikut adalah panduannya.

Service Boundaries: Satu Layanan = Satu Bounded Context

DDD dan Ubiquitous Language

Pilar pertama berasal dari Domain-Driven Design (DDD). Setiap layanan harus mewakili satu bounded context: sebuah batas eksplisit di mana sebuah konsep domain memiliki makna yang konsisten. Di dalam satu context, tim memakai ubiquitous language — satu kosa kata yang sama antara product owner, engineer, dan kode.

Contoh: kata "order" punya makna berbeda di context yang berbeda. Di order-service, order adalah status transaksi. Di payment-service, "order" hanyalah referensi order_id — ia tidak punya field status order, hanya amount yang harus dibayar. Mencampur keduanya dalam satu tabel (seperti di monolith) membuat makna satu domain bocor ke domain lain.

Aturan Praktis Menentukan Batas

Beberapa heuristic yang lazim dipakai:

  • Satu layanan bertanggung jawab atas satu alur bisnis yang kohesif — jangan membuat layanan "anak" yang tinggal fetch data dari layanan lain tanpa alasan domain.
  • Data yang selalu berubah bersama harus tinggal bersama — jika dua entitas tak pernah berubah tanpa yang lain, kemungkinan mereka satu context.
  • Batasi jumlah layanan — untuk tim kecil, 5-15 layanan sudah banyak; jangan pecah demi estetika.
Bounded contexts tokokita
auth-service         # identitas: user, credential, token
product-service      # katalog: produk, kategori, stok, inventory
cart-service         # keranjang: session cart, qty, snapshot harga
order-service        # pesanan: order, order_items, state machine
payment-service      # pembayaran: transaksi, status payment, amount
notification-service # notifikasi: email, sms, template pesan

Database per Service

Prinsip: Jangan Berbagi Schema Lintas Layanan

Setiap layanan memiliki database atau schema sendiri. order-service tidak membaca tabel users milik auth-service secara langsung; ia menyimpan user_id sebagai foreign key konseptual tanpa join. Tidak ada service lain yang boleh mengeksekusi SQL ke database milik layanan lain — semua akses harus lewat API layanan pemilik data.

Konsekuensinya tegas dan harus diterima apa adanya:

  • Tidak ada join lintas layanan. Jika perlu data gabungan, gunakan agregasi di gateway (API composition) atau duplikasi data yang disengaja (read model — episode 14).
  • Konsistensi lintas layanan tidak bisa ACID. Transaksi lintas layanan butuh saga (episode 13) atau event-driven eventual consistency (episode 12).
  • Fragmentasi data — satu entitas utuh tersebar; butuh disiplin supplier/owner tiap data.
Database per service di tokokita
auth_service_db   → users, refresh_tokens
product_service_db → products, categories, inventories
order_service_db  → orders, order_items
payment_service_db → payments, transactions
notification_service_db → notifications, outbox_emails

Caution

Kesalahan umum: membiarkan beberapa layanan memakai satu database yang sama demi "praktis". Ini menghancurkan independensi — satu schema change bisa membawa turun banyak layanan dan mengubah microservices menjadi distributed monolith (satu database, banyak jaringan). Prinsipnya: jika sebuah layanan tidak bisa men-deploy dan berjalan tanpa meminta izin schema ke layanan lain, batasnya salah.

API Gateway / BFF

Semua client (web, mobile app) masuk lewat satu pintu: API Gateway. Gateway bertanggung jawab atas:

  • Routing — meneruskan /api/auth/* ke auth-service, /api/products/* ke product-service.
  • Auth & rate-limit — memvalidasi token sekali di depan, bukan di tiap layanan.
  • TLS termination — enkripsi dihapus sekali di gateway; internal boleh plain dengan mTLS.
  • Response aggregation — menggabungkan beberapa service untuk satu halaman.

BFF (Backend-for-Frontend) adalah varian di mana tiap jenis client punya gateway khusus sendiri — misalnya bff-web dan bff-mobile — karena kebutuhan payload keduanya berbeda. BFF dipakai bila client mobile dan web mulai memaksa gateway melakukan terlalu banyak hal.

Semua masuk lewat satu pintu
Client (web/app) → api-gateway
                     ├── /api/auth/*    → auth-service
                     ├── /api/products/* → product-service
                     ├── /api/cart/*    → cart-service
                     └── /api/orders/*  → order-service

Communication Styles

Dua gaya komunikasi antar layanan:

Sinkron: HTTP/REST atau gRPC

Request → response dalam satu waktu, layanan pemanggil memblokir sampai jawaban tiba. Cocok untuk operasi yang memang butuh jawaban langsung: login, cek detail produk, submit order. Dipakai untuk command yang butuh konfirmasi.

Asinkron: Event Bus (Kafka/Redis/NATS)

Layanan pemanggil mengirim event dan tidak menunggu. Event dikonsumsi oleh siapa pun yang peduli (notification, analytics). Ini memutus coupling langsung antar layanan dan memberi eventual consistency. Dipakai untuk hal-hal seperti "user baru terdaftar" — tidak ada yang perlu menunggu apakah email selamat datang berhasil terkirim.

Perbandingan singkat:

AspekSinkronAsinkron
CouplingLangsung ke pemilik dataLepas (decoupled)
KonsistensiLangsungEventual
KegagalanFailure langsung terlihatBuffer di event bus
Cocok untukRequest-response (command)Notifikasi, integrasi, fan-out

Studi Kasus Utama Series: tokokita

Sepanjang series kita membangun tokokita, e-commerce dengan alur utama: browse produk → keranjang → checkout → bayar → notifikasi email. Tujuh proses berjalan:

100%

Layani ini ditenagai PostgreSQL (data), Redis (cache/session), dan Kafka (event bus). Di episode 3 kita akan menuliskan struktur monoreponya.

Penutup

Episode 2 meletakkan empat pilar arsitektur microservices:

  • Service boundaries: satu layanan = satu bounded context (DDD, ubiquitous language).
  • Database per service: tidak ada join lintas layanan; data pemilik layanan dihormati.
  • API gateway/BFF: satu pintu untuk route, auth, rate-limit, TLS, dan agregasi.
  • Komunikasi: sinkron (REST/gRPC) untuk request-response; asinkron (event bus) untuk decoupling.

Studi kasus tokokita siap dibangun dengan tujuh proses + gateway.

Di episode 3 selanjutnya, kita akan setup struktur projek tokokita (monorepo) — membandingkan monorepo vs polyrepo, membangun struktur folder lengkap dengan shared packages, dan menjalankan environment dev (PostgreSQL, Redis, Kafka) lewat Docker Compose. Sampai jumpa di episode 3!