Jawaban singkat untuk pertanyaan yang paling sering diajukan pembaca tentang topik ini.
01Apa itu system design dalam pengembangan software?
System design adalah keputusan tentang bagaimana komponen, data, dan interface sebuah sistem disusun agar memenuhi requirement beban, reliabilitas, dan biaya. Satuan kerjanya adalah keputusan dengan trade-off, misalnya cache yang mempercepat baca tetapi bisa menyajikan data basi. Ini dikerjakan sebelum dan bersamaan dengan coding, bukan sebagai penggantinya.
02Bagaimana cara mulai belajar system design dari nol?
Mulai dari kosakata: latency, throughput, availability, consistency, dan idempotency. Lalu baca satu buku mendalam seperti Designing Data-Intensive Applications dan terapkan ide-idenya pada sistem yang sudah Anda kenal. Berlatih dengan menulis design note satu halaman untuk fitur kecil sebelum mengodekannya.
03Apakah developer junior perlu skill system design?
Anda tidak perlu merancang sistem terdistribusi besar, tetapi memahami mengapa sistem yang Anda kerjakan dibangun seperti itu sangat membantu. Memperkirakan beban dan bertanya apa yang terjadi saat gagal berguna sejak proyek pertama. Kedalamannya tumbuh seiring Anda memegang fitur yang lebih besar.
04Bagaimana cara memperkirakan beban dalam system design?
Kalikan jumlah pengguna atau outlet dengan aksi per hari, bagi 86.400 detik untuk laju rata-rata, lalu terapkan peak factor yang dinyatakan. Tambahkan ukuran row dikali volume untuk storage, dan pakai Little's law untuk mengetahui request in flight. Tulis setiap asumsi agar orang lain bisa mengujinya.
05Kapan sebaiknya menambah cache, queue, atau load balancer?
Tambahkan hanya ketika Anda bisa mengukur gejala yang diselesaikannya: baca berulang untuk cache, pekerjaan lambat yang memblokir request untuk queue, CPU jenuh untuk instance tambahan di belakang load balancer. Setiap komponen membawa biaya seperti data basi, hasil eventual, atau server stateless. Jika belum ada gejala, tidak menambah apa pun adalah desain yang sah.
System design adalah proses memutuskan bagaimana komponen, data, dan interface sebuah sistem software disusun agar memenuhi requirement beban, reliabilitas, dan biaya yang sudah dinyatakan. Cara belajarnya: hitung beban dengan aritmetika, sebutkan failure mode, pilih building block paling sederhana yang tahan terhadapnya, lalu tulis trade-off-nya.
Pertama kali diminta menggambar arsitektur sebelum menulis kode, saya menggambar lima kotak dan tiga panah lalu merasa sudah selesai. Lalu ada yang bertanya apa yang terjadi kalau host database mati di jam sibuk, dan gambar itu tidak punya jawaban.
Post ini menjawab pertanyaan yang banyak dicari: apa itu system design dan bagaimana cara mempelajarinya. Istilahnya merujuk definisi yang dikutip dari sumber, sisanya berupa aritmetika yang bisa Anda cek sendiri. Contohnya POS multi-outlet hipotetis, jenis masalah yang dekat dengan pekerjaan saya di ERP, POS, dan NestJS di atas Postgres, Redis, dan Docker. Semua angka input ditandai sebagai asumsi, bukan hasil pengukuran.
Apa itu system design dalam pengembangan software?
System design adalah pekerjaan menentukan bagian-bagian sebuah sistem, cara mereka berkomunikasi, dan data apa yang mereka pegang, supaya keseluruhan sistem memenuhi requirement yang bisa dinyatakan. Artikel Wikipedia tentang systems design menggambarkannya sebagai pemahaman atas komponen dan interaksi di antara mereka. Dalam software, artinya service, database, queue, cache, dan kontrak di antara semuanya.
Bedanya dengan menulis kode ada pada satuan kerjanya: yang dikerjakan adalah keputusan, bukan fungsi. Setiap keputusan punya biaya di tempat lain. Cache membuat baca cepat tetapi data bisa basi. Queue membuat request cepat tetapi hasilnya eventual. System design berarti memilih biaya mana yang sanggup Anda tanggung sebelum membayarnya di production.
Apa saja yang sebenarnya diputuskan saat mendesain sistem?
Lima keputusan mencakup sebagian besar pekerjaannya, dan urutannya penting karena masing-masing membatasi yang berikutnya.
Requirement: apa yang harus dilakukan, serta seberapa cepat, seberapa available, dan seberapa benar. Requirement yang tidak dinyatakan adalah tempat desain gagal diam-diam.
Beban: berapa request per detik, berapa data per tahun, dan seberapa bursty. Ini aritmetika, bukan opini.
Model data: entitas apa saja, store mana yang memilikinya, dan apa yang harus konsisten pada saat yang sama.
Interface: bentuk API, termasuk apa yang aman di-retry oleh client.
Kegagalan: apa yang rusak lebih dulu, apa yang dilihat pengguna, dan berapa kehilangan yang bisa diterima. Panduan cloud seperti AWS Well-Architected Framework memisahkan reliability, performance efficiency, cost optimization, dan security sebagai pilar tersendiri justru karena mereka saling bertarik-tarikan.
Perhatikan bahwa scaling tidak muncul sebagai butir tersendiri. Ia muncul dari estimasi beban. Banyak desain gagal karena menjawab pertanyaan scaling sebelum mengukur apakah masalahnya ada.
Bagaimana memperkirakan beban sebelum menggambar kotak apa pun?
Tulis asumsi sebagai kode atau tabel dan biarkan aritmetikanya bicara. Di bawah ini adalah rollout hipotetis 200 outlet dengan 300 transaksi per outlet per hari. Peak factor, ukuran row, dan service time adalah asumsi yang saya pilih sebagai ilustrasi; ganti dengan angka Anda sendiri begitu ada data nyata.
// Back-of-envelope sizing for a hypothetical multi-outlet POS.
// Every input is an ASSUMPTION you state out loud; every output is arithmetic.
const outlets = 200;
const txPerOutletPerDay = 300;
const secondsPerDay = 86_400;
const peakFactor = 10; // assumption: the busiest second is ~10x the mean
const bytesPerTx = 2_000; // assumption: header + ~6 lines + payments, as rows
const serviceTimeSeconds = 0.05; // assumption: 50 ms of work per request
const txPerDay = outlets * txPerOutletPerDay; // 60,000
const meanTps = txPerDay / secondsPerDay; // 0.694...
const peakTps = meanTps * peakFactor; // 6.94...
// Little's law: L = lambda * W (items in the system = arrival rate * time each spends in it)
const inFlight = peakTps * serviceTimeSeconds; // 0.347... requests in flight
const gbPerYear = (txPerDay * bytesPerTx * 365) / 1_000_000_000; // 43.8 GB
// Reading: ~7 writes/s at peak and ~44 GB/year is a single-Postgres problem.
// The design question is NOT "how do we scale?" but "what happens when it fails?"
Hasilnya yang berguna. Sekitar 7 write per detik saat peak, kurang dari setengah request in flight menurut Little's law (pekerjaan yang sedang berjalan sama dengan laju kedatangan dikali waktu di dalam sistem), dan sekitar 44 GB per tahun. Itu muat di satu instance Postgres yang dikonfigurasi baik. Jadi masalah desain yang menarik adalah backup, retry, dan failover, bukan sharding. Seandainya hasilnya 7.000 write per detik, desainnya akan sama sekali berbeda, dan itulah alasan menghitung lebih dulu.
Bulatkan secara agresif dan tulis asumsinya di sebelah angka. Reviewer bisa mendebat peak factor 10x dalam hitungan detik. Mereka tidak bisa mendebat klaim samar bahwa sistem harus bisa scale.
Building block mana yang menyelesaikan masalah apa?
Komponen adalah jawaban atas gejala yang terukur, bukan hiasan. Pakai tabel ini sebagai checklist keputusan: cari gejala yang benar-benar bisa Anda amati, lalu lihat berapa biaya perbaikannya.
Gejala yang bisa diukur
Building block
Biayanya
Row yang sama dibaca berulang kali dan database jadi bottleneck
Cache seperti Redis di depan database
Data basi dan logika invalidation
Pekerjaan lambat (PDF, email, sync pihak ketiga) memblokir HTTP request
Queue plus worker process
Hasil eventual, retry, penanganan duplikat
Satu proses aplikasi menghabiskan CPU
Lebih banyak instance di belakang load balancer
Server harus stateless, session pindah dari memori
Query makin lambat seiring tabel membesar
Index dulu, read replica belakangan
Write lebih lambat, dan replica lag pada read
Satu host database adalah single point of failure
Replication dengan failover, plus backup yang sudah diuji
Kompleksitas operasional dan kemungkinan ada jendela kehilangan data saat failover
Baca kolom kanan dua kali. Setiap baris membeli satu properti dengan membayar properti lain, dan desain yang hanya menyebut keuntungan adalah brosur penjualan, bukan desain. Kalau belum ada gejala di kolom kiri yang benar, jumlah komponen baru yang tepat adalah nol. Di satu VPS yang menjalankan NestJS, Postgres, dan Redis di Docker, itu sering jadi jawaban yang jujur.
Bagaimana cara belajar system design sebagai developer?
Pelajari sebagai siklus estimasi, desain, rusak, dan revisi, bukan sebagai katalog arsitektur terkenal. Urutan praktisnya:
Pelajari kosakata dari sumber netral: latency, throughput, availability, consistency, idempotency. Wikipedia dan panduan arsitektur dari vendor cloud sudah cukup untuk memulai.
Baca satu buku mendalam sampai tamat. Designing Data-Intensive Applications karya Martin Kleppmann membahas storage, replication, partitioning, dan consistency dengan cara yang menjelaskan mengapa building block berperilaku seperti itu.
Ambil sistem yang sudah Anda kerjakan dan jalankan aritmetika beban padanya. Angka nyata dari log Anda sendiri mengalahkan contoh buku mana pun.
Tulis design note satu halaman untuk fitur kecil sebelum mengodekannya, lengkap dengan satu alternatif yang ditolak dan satu failure mode.
Rusakkan desain Anda sendiri di atas kertas: matikan tiap komponen secara bergiliran dan catat apa yang dilihat pengguna.
Latihan gaya interview punya tempatnya, tetapi itu melatih kecepatan menggambar kotak. Siklus catat-lalu-rusakkan melatih penilaian yang dibutuhkan pekerjaan nyata.
Seperti apa design note satu halaman?
Cukup pendek untuk dibaca dalam lima menit, cukup spesifik untuk bisa salah. Ini template yang akan saya pakai untuk fitur sinkronisasi POS yang dihitung di atas. Angka RPO dan RTO adalah target yang disepakati tim, bukan hasil pengukuran.
# Design note: receipt sync for outlet POS (one page, written BEFORE code)
## 1. Requirements
Functional : an outlet can sell while offline; sales reach head office within 5 min of reconnect.
Non-func : peak ~7 writes/s (see sizing); no lost sale; no double-posted sale.
## 2. Data
sale(id uuid PK, outlet_id, total_idr bigint, created_at timestamptz) -- money as integer rupiah
sale_line(sale_id FK, sku, qty, price_idr)
## 3. Interface
POST /v1/sales Idempotency-Key: <sale uuid> -> 201 first time, 200 on replay
## 4. Failure modes
Network drops mid-request -> client retries -> idempotency key makes the retry safe.
DB host dies -> restore from backup; accepted RPO 15 min, RTO 1 h.
## 5. Rejected alternatives
Kafka : one consumer, ~7 msg/s; operating it costs more than the problem.
Microservices: one team; a network hop buys nothing yet.
## 6. Revisit when
peak > 200 writes/s, or a second team owns part of the schema.
Dua bagian mengerjakan sebagian besar pekerjaan. Failure modes memaksa Anda menyatakan apa yang terjadi saat retry, makanya baris interface membawa idempotency key. Rejected alternatives mencatat bahwa Anda sudah mempertimbangkan Kafka atau microservices dan menolaknya dengan alasan yang terkait angka beban. Enam bulan kemudian, bagian itu menghemat satu perdebatan.
Apa kesalahan umum pemula dalam system design?
Yang paling umum adalah mendesain untuk beban yang tidak ada. Memakai sharding, Kafka, atau service mesh karena arsitektur perusahaan besar, tanpa estimasi sendiri, menambah biaya operasional yang menurut sizing di atas tidak Anda butuhkan.
Jangan menyalin arsitektur perusahaan besar hanya karena muncul di sebuah talk. Arsitektur itu dibentuk oleh beban, ukuran tim, dan riwayat kegagalan mereka. Aritmetika Anda harus membenarkan setiap komponen, dan komponen tanpa gejala terukur di baliknya adalah beban.
Kesalahan kedua adalah mengabaikan kegagalan dan hanya bertanya bagaimana membuatnya cepat. Ketiga, membiarkan trade-off tidak tertulis, sehingga engineer berikutnya tidak bisa membedakan pilihan sengaja dari kecelakaan. Desain yang menyatakan batasnya, dan kondisi kapan Anda akan meninjaunya lagi, lebih mudah dipercaya daripada yang mengaku bisa scale ke segalanya.
System design adalah kebiasaan memutuskan dengan angka dan menuliskan biaya tiap keputusan. Hitung bebannya, sebutkan kegagalannya, tambahkan komponen hanya ketika gejala terukur menuntutnya, dan catat alternatif yang Anda tolak. Lakukan itu pada sistem nyata yang Anda kenal, dan Anda sudah melatih keterampilannya.