Topik ini mendefinisikan system design sebagai disiplin, menelusuri pergeseran dari aplikasi yang seluruh kodenya berada dalam satu proses menuju kumpulan layanan yang saling berkomunikasi melalui jaringan, lalu menutup dengan perbedaan antara mendesain sistem untuk wawancara dan untuk production. Setelah membacanya, istilah dasar seperti monolit, layanan, dan fan-out sudah tersedia untuk menggambarkan sebuah arsitektur secara terstruktur. Percobaan kecil berupa diagram dan simulasi disertakan agar pergeseran arsitektur tersebut terasa konsekuensinya, bukan sekadar dibayangkan.
Definisi dan lingkup system design#
System design adalah proses merancang struktur sebuah sistem perangkat lunak berskala besar, mulai dari pemilihan komponen, cara komponen saling berkomunikasi, hingga penentuan bagaimana setiap keputusan memengaruhi kualitas sistem secara keseluruhan. Kualitas di sini bukan berarti fitur baru, melainkan sifat seperti kapasitas menahan trafik, kecepatan respons, dan biaya operasional. Aplikasi kecil memang bisa selesai setelah satu fungsi ditulis dan dijalankan pada satu mesin. Masalah baru muncul ketika jumlah pengguna, volume data, dan jumlah insinyur yang terlibat bertambah, karena keputusan yang tadinya tanpa konsekuensi kini menentukan apakah sistem tetap mampu melayani atau justru jatuh.
Proses desain selalu dimulai dari kebutuhan. Kebutuhan fungsional menyatakan apa yang harus dilakukan sistem, sedangkan kebutuhan nonfungsional menyatakan seberapa baik sistem melakukannya, misalnya berapa banyak permintaan per detik yang harus ditahan dan seberapa cepat respons harus tiba. Keluaran proses ini berupa arsitektur, yaitu gambaran komponen beserta aliran data di antaranya, disertai alasan atas setiap pilihan yang menimbulkan tradeoff. Satu keputusan jarang lebih baik dalam segala kondisi, sehingga desain selalu merupakan pertukaran antara kecepatan, biaya, dan kerumitan operasional.
Dari monolit ke layanan terdistribusi#
Banyak aplikasi dimulai sebagai monolit, yaitu aplikasi yang seluruh logikanya berada di dalam satu proses dan menyimpan data pada satu basis data. Bentuk ini sederhana karena panggilan antarfungsi berlangsung langsung di dalam memori, deployment hanya melibatkan satu paket, dan pengujian bisa dilakukan tanpa menyediakan banyak komponen. Untuk skala kecil hingga menengah, monolit tetap menjadi pilihan yang masuk akal.
Batas mulai terasa ketika pertumbuhan tidak merata. Modul yang paling sering dipanggil menuntut tambahan kapasitas, tetapi monolit hanya bisa diskalakan sebagai satu kesatuan, sehingga seluruh proses harus digandakan meskipun yang sibuk hanya satu bagian. Deployment juga menjadi rawan karena perubahan sekecil apa pun mengharuskan seluruh aplikasi dibangun ulang dan dirilis. Solusi yang lazim adalah memecah aplikasi menjadi layanan (service), yaitu unit perangkat lunak yang berjalan pada proses tersendiri, dapat dideploy secara independen, dan berkomunikasi melalui jaringan.
Diagram berikut membandingkan kedua bentuk tersebut. Di sisi kiri, klien berbicara dengan satu aplikasi monolit yang memanggil fungsinya secara langsung. Di sisi kanan, permintaan masuk ke layanan utama yang kemudian memanggil tiga layanan lain, dan setiap garis pada sisi kanan merupakan komunikasi jaringan.
Panggilan fungsi menjadi panggilan jaringan#
Pergeseran ke layanan mengubah sifat panggilan yang paling mendasar. Panggilan fungsi di dalam satu proses berlangsung dalam orde mikrodetik dan kemungkinan gagalnya nyaris tidak dipertimbangkan, sedangkan panggilan antarlayanan menempuh jaringan, berlangsung dalam orde milidetik, dan dapat terputus karena gangguan jaringan atau layanan yang kelebihan beban. Karena itu kode yang memanggil layanan lain perlu menangani timeout, yaitu batas waktu tunggu, serta retry, yaitu percobaan ulang yang dirancang hati-hati agar tidak memperparah keadaan.
Satu permintaan dari browser pun bisa memicu banyak panggilan, pola yang disebut fan-out. Apabila panggilan dijalankan satu per satu, latensinya berjumlah total, sedangkan apabila dijalankan serentak, latensinya sama dengan durasi panggilan yang paling lambat. Berkas berikut mensimulasikan satu permintaan yang memerlukan data dari tiga layanan.
# Perbandingan panggilan fungsi lokal dengan panggilan jaringan antarlayanan.
# Durasi berupa estimasi yang lazim, dinyatakan dalam milidetik.
PANGGILAN_JARINGAN = {
"layanan-profil": 40,
"layanan-pesanan": 120,
"layanan-rekomendasi": 80,
}
DURASI_FUNGSI_LOKAL = 0.01 # panggilan fungsi di dalam satu proses
sekuensial = sum(PANGGILAN_JARINGAN.values())
paralel = max(PANGGILAN_JARINGAN.values())
print(f"Panggilan fungsi lokal : {DURASI_FUNGSI_LOKAL} ms")
print(f"Tiga layanan secara sekuensial : {sekuensial} ms")
print(f"Tiga layanan secara paralel : {paralel} ms")
print(f"Rasio sekuensial terhadap paralel: {sekuensial / paralel}")Panggilan fungsi lokal : 0.01 ms
Tiga layanan secara sekuensial : 240 ms
Tiga layanan secara paralel : 120 ms
Rasio sekuensial terhadap paralel: 2.0Keluaran menunjukkan perbedaan yang besar. Tiga panggilan yang dijalankan sekuensial memakan 240 ms, sedangkan versi paralel cukup 120 ms, yakni durasi panggilan yang paling lambat. Selisih semacam ini menjelaskan mengapa banyak desain berusaha memperkecil jumlah panggilan jaringan dan menjalankan panggilan yang tersisa secara paralel. Angka 0,01 ms untuk panggilan fungsi lokal juga mengingatkan bahwa perpindahan ke layanan menambah biaya yang tidak kecil, sehingga pemecahan layanan tidak boleh dilakukan tanpa alasan yang jelas.
Desain untuk wawancara dan untuk production#
Latihan system design yang paling banyak dibahas adalah wawancara desain sistem. Formatnya berupa percakapan 35 sampai 45 menit, dan kandidat diminta merancang sebuah sistem, misalnya pemendek URL atau layanan berbagi pesan, di atas papan tulis. Penilaiannya menekankan proses berpikir, yaitu bagaimana kebutuhan diklarifikasi, estimasi dibuat, dan tradeoff dijelaskan, bukan sekadar hasil akhirnya.
Pekerjaan nyata memberi tekanan yang berbeda. Keputusan desain di production bertahan bertahun-tahun, diukur dengan data nyata, dan menimbulkan konsekuensi biaya serta beban siaga. Prosesnya berlangsung melalui dokumen desain yang direview rekan kerja, kemudian diimplementasikan bertahap dengan pengukuran pada setiap langkah. Tabel berikut merangkum perbedaannya.
| Aspek | Wawancara | Production |
|---|---|---|
| Rentang waktu | satu sesi 35-45 menit | keputusan bertahan bertahun-tahun |
| Sasaran penilaian | proses berpikir dan kualitas tradeoff | angka sasaran yang terpenuhi dan biaya yang terkendali |
| Kualitas angka | kasar, tetapi konsisten secara internal | diukur dari data nyata dan diverifikasi melalui monitoring |
| Konsekuensi keliru | tidak berdampak pada pengguna | insiden, tagihan membengkak, beban siaga bertambah |
| Bentuk keluaran | sketsa di papan tulis | dokumen desain, implementasi bertahap, dan metrik |
Perbedaan terbesar terletak pada umpan balik. Di wawancara tidak ada pengguna yang benar-benar terdampak, sehingga angka kasar yang konsisten sudah cukup. Di production, setiap sasaran harus dapat diverifikasi melalui monitoring, dan desain yang keliru muncul dalam bentuk insiden, tagihan yang membengkak, atau keterlambatan rilis. Karena itu jalur ini menekankan kebiasaan menyatakan angka sejak awal, bukan sekadar menggambar arsitektur yang tampak canggih.
Kesalahan umum#
Kesalahan berikut sering muncul ketika materi ini dipraktikkan pertama kali, baik pada latihan wawancara maupun pada pekerjaan nyata.
- Melompat ke solusi sebelum kebutuhan dinyatakan. Desain dibuka dengan menyebut cache, load balancer, atau queue tanpa angka kebutuhan, sehingga tidak ada dasar untuk menilai pilihan itu. Padahal angka kasar sekalipun sudah cukup untuk menilai sebuah pilihan. Perbaikannya: mulai dari kebutuhan nonfungsional dan estimasi kasar, lalu pilih komponen yang menjawab kebutuhan tersebut.
- Menganggap panggilan jaringan sama andalnya dengan panggilan fungsi. Desain tanpa penanganan timeout dan retry berperilaku tidak terduga ketika satu layanan lambat, karena permintaan menumpuk sambil menunggu. Perbaikannya: tetapkan batas waktu dan perilaku percobaan ulang pada setiap sambungan antarlayanan sejak desain pertama.
- Meniru arsitektur perusahaan besar untuk sistem kecil. Memecah sistem menjadi banyak layanan sejak awal menambah kerumitan deployment dan pemantauan yang belum diperlukan. Kerumitan yang ditambahkan lebih dahulu sulit dilepaskan kemudian. Perbaikannya: mulai dari monolit yang terstruktur rapi, kemudian pecah menjadi layanan ketika tekanan skalabilitas atau ukuran tim benar-benar menuntut.
Ringkasan#
- System design merancang struktur sistem berskala besar dan menyatakan setiap keputusan sebagai tradeoff antara kecepatan, biaya, dan kerumitan operasional.
- Monolit menampung seluruh logika dalam satu proses dan tetap masuk akal untuk skala kecil, sedangkan layanan terdistribusi menukar kesederhanaan dengan skalabilitas dan deployment yang independen.
- Panggilan antarlayanan berlangsung dalam milidetik, dapat gagal, dan menumpuk saat fan-out, sehingga timeout, retry, dan eksekusi paralel menjadi bagian dari desain.
- Wawancara menilai proses berpikir dengan angka kasar, sedangkan production menuntut angka yang terukur, dapat diverifikasi, dan dipertanggungjawabkan.
Referensi#
- The System Design Primer — Donnemartin (GitHub) — Materi terbuka yang membahas pendekatan soal desain sistem, estimasi kasar, dan komponen arsitektur yang umum.
- MonolithFirst — Martin Fowler — Argumen mengapa banyak sistem sebaiknya dimulai sebagai monolit sebelum dipecah menjadi layanan.