- Memisahkan kode menjadi microservices terlalu dini di startup tahap awal menyebabkan penurunan produktivitas tim yang serius dan peningkatan kompleksitas
- Arsitektur monolitik memberikan optimasi untuk bertahan hidup melalui deployment yang sederhana, rilis fitur baru yang cepat, dan kolaborasi yang efisien
- Microservices hanya memberikan manfaat pemisahan saat ada kebutuhan skalabilitas besar, workload yang beragam, atau kebutuhan runtime yang terpisah
- Pemisahan layanan yang berlebihan, repositori yang bertebaran, lingkungan pengembangan lokal yang tidak stabil, dan ketidaksesuaian tech stack berujung pada perlambatan dan turunnya moral tim
- Startup sebaiknya memulai dengan monolit dan mengambil pendekatan hati-hati dengan memisahkan hanya saat bottleneck yang jelas muncul
Pendahuluan dan latar belakang
- Kelangsungan hidup startup ditentukan oleh iterasi yang cepat, pengiriman fitur baru, dan penciptaan nilai bagi pengguna
- Pemilihan arsitektur dasar proyek, tech stack, dan bahasa pemrograman memengaruhi kecepatan tim
- Adopsi microservices terlalu dini secara formal terlihat canggih, tetapi dalam praktik justru menyebabkan penurunan produktivitas, layanan yang belum matang, dan kompleksitas berlebihan
- Data: muncul berbagai biaya pengembangan seperti orkestrasi layanan, masalah Docker/skrip, CI/CD yang terduplikasi, coupling antar layanan, biaya observability, dan pengujian yang tersebar
- Alih-alih gegabah menuju arsitektur yang rumit, penting untuk menekankan arsitektur yang pragmatis
Kekuatan monolit
- Baik itu SaaS maupun wrapper database sederhana, aplikasi akan makin kompleks seiring waktu, tetapi arsitektur monolit lebih mudah dipertahankan agar tetap sederhana dan fleksibel
- Deployment mudah, didukung framework populer (Django, ASP.Net, Nest.js, dll.), dan mendapat banyak manfaat dari komunitas open source
- Contoh nyata: sebuah startup properti menggunakan monolit Laravel untuk dengan mudah mencapai banyak integrasi pihak ketiga dan perluasan fitur
- Tanpa memperkenalkan infrastruktur yang rumit atau memecah ke microservices, tim bisa fokus memenuhi kebutuhan bisnis dan ekspektasi
- Pelajaran: kesederhanaan arsitektur membantu tim fokus pada deployment, dan skalanya pun cukup asalkan berhati-hati agar modularisasi internal tidak gagal
Apakah microservices selalu yang terbaik?
- Banyak engineer menganggap microservices adalah jawaban terbaik, tetapi kenyataannya nilainya baru benar-benar terlihat saat ada alasan khusus seperti kebutuhan scaling
- Pada tahap dengan anggota sedikit, skala kecil, dan perubahan cepat, pendekatan ini justru menimbulkan efek sebaliknya berupa infrastruktur yang terduplikasi, pengembangan lokal yang lambat, dan siklus iterasi yang lambat
- Perusahaan seperti Segment juga pernah mengalami transisi akibat struktur yang tidak efisien
- Pelajaran: microservices hanyalah alat untuk menyelesaikan bottleneck, bukan template awal
Mengapa microservices sering gagal khususnya pada tahap awal
1. Batas layanan yang arbitrer
- Upaya membagi layanan berdasarkan logika bisnis dengan meminjam teori domain-driven design dan clean architecture → batas antara logika nyata dan layanan sering tidak benar-benar selaras
- Contoh: pemisahan pengguna, autentikasi, dan otorisasi meningkatkan kompleksitas deployment serta kesulitan pengembangan API
- Pemisahan pada tahap ketika bottleneck nyata belum muncul membuat sistem menjadi tidak stabil dan lambat
- Mensimulasikan pemisahan di masa depan dengan flag atau toggle internal, sambil mengeksplorasi batas yang organik alih-alih buru-buru mengerjakan infrastruktur, lebih efektif
- Pelajaran: keputusan pemisahan harus didasarkan pada bottleneck nyata, bukan teori
2. Repositori/infrastruktur yang berlebihan
- Gaya kode, pengujian, konfigurasi, dokumentasi, dan CI/CD semuanya bertambah seiring jumlah layanan
- Jika menggunakan struktur monorepo, semua konfigurasi bisa dikelola di satu tempat untuk meningkatkan konsistensi kode dan efisiensi kolaborasi
- Dalam kasus Node.js, alat seperti
nx atau turborepo mempermudah pengelolaan dependensi dan build antar layanan internal
- Kekurangannya termasuk dependensi yang rumit, kebutuhan tuning performa CI, dan perlunya alat build yang lebih cepat
- Ekosistem Go juga dapat dikelola dalam satu workspace pada awalnya, lalu mempertimbangkan pemisahan modul saat skala membesar
- Pelajaran: tim kecil bisa menghemat waktu dengan monorepo dan infrastruktur bersama
3. Lingkungan pengembangan lokal yang tidak stabil
- Waktu yang berlebihan untuk menjalankan secara lokal, skrip yang rumit, dan dependensi spesifik sistem menyebabkan onboarding melambat dan produktivitas menurun
- Kurangnya dokumentasi, masalah kompatibilitas, dan hack khusus OS (misalnya skrip khusus macOS) menjadi hambatan
- Dalam satu proyek, kompleksitas Docker dikurangi lewat proxy Node.js sehingga waktu onboarding developer berkurang
- Pelajaran: jika aplikasi hanya berjalan di satu OS, produktivitas tim pada akhirnya bergantung pada keandalan satu laptop
4. Ketidaksesuaian tech stack
- Node.js dan Python bagus untuk iterasi cepat, tetapi dalam lingkungan microservices sering memunculkan masalah ketidaksesuaian build/runtime
- Go unggul dalam binary statis, build cepat, dan kesederhanaan operasional
- Pemilihan tech stack harus dilakukan dengan hati-hati sejak awal, dan jika perlu, bahasa campuran bisa digunakan lewat protokol seperti gRPC
- Jika tidak ada kebutuhan khusus seperti ML atau ETL, mencampur stack justru hanya menambah kompleksitas
- Pelajaran: pilih stack yang sesuai dengan realitas tim, bukan sekadar ambisi
5. Kompleksitas tersembunyi: komunikasi dan monitoring
- Dalam microservices, service discovery, versioning API, distributed tracing, pengelolaan log terpusat, dan lain-lain menjadi kebutuhan wajib
- Jika di monolit pelacakan bug atau gangguan cukup dengan satu stack trace, di lingkungan terdistribusi semuanya jauh lebih rumit
- Untuk melakukannya dengan benar, perlu adopsi alat khusus seperti OpenTelemetry dan pembangunan stack observability
- Harus disadari bahwa sistem terdistribusi adalah investasi wajib untuk tantangan engineering tambahan
Situasi ketika microservices memang efektif
- Isolasi workload: memisahkan pekerjaan asinkron tertentu seperti pemrosesan gambar atau OCR bisa efisien
- Ketimpangan kebutuhan scaling: jika web API dan workload ML memiliki kebutuhan hardware dan operasi yang berbeda, masing-masing sebaiknya dipisah
- Kebutuhan runtime yang berbeda: komponen seperti kode legacy C++ yang tidak kompatibel dengan runtime aplikasi utama sebaiknya dipertahankan sebagai layanan terpisah
- Dari contoh organisasi engineering besar (misalnya Uber), pendekatan ini hanya cocok ketika ada kebutuhan organisasional yang jelas dan kemampuan operasi yang matang
- Bahkan di tim kecil pun, pemisahan kadang praktis jika pengelolaannya sederhana seperti layanan analitik eksternal
- Pelajaran: adopsi hanya pada workload yang benar-benar memiliki manfaat pemisahan yang jelas
Panduan praktis untuk startup
- Mulailah dengan monolit, dan fokus bekerja dengan framework yang sudah terbukti
- Satu repositori lebih menguntungkan bagi tim tahap awal dari sisi efisiensi operasional, pengelolaan, dan keamanan
- Menyederhanakan lingkungan pengembangan lokal itu penting, dan jika sulit, dokumentasi serta video panduan yang detail wajib disediakan
- Berinvestasilah lebih awal di CI/CD untuk mengotomatisasi pekerjaan berulang dan mengurangi beban mental tim
- Pisahkan secara selektif hanya saat bottleneck yang jelas muncul, dan jika tidak, fokuslah pada modularisasi di dalam monolit serta penguatan pengujian
- Tujuan utama adalah menjaga kecepatan pengembangan
- Pelajaran: mulai dari kesederhanaan, lalu scale sesuai kebutuhan pemisahan yang nyata
Jika tetap harus memakai microservices
- Evaluasi tech stack dan investasi pada alat developer experience: perlu menyiapkan otomatisasi per layanan, skrip yang jelas, dan alat manajemen deployment terintegrasi
- Protokol komunikasi layanan yang andal dan standardisasi: perlu memahami tambahan implementasi seperti konsistensi skema pesan, dokumentasi, dan penanganan error
- Stabilisasi infrastruktur testing: pengujian unit, integrasi, dan E2E harus diperluas agar sesuai dengan pemisahan layanan
- Pertimbangkan library bersama: kode umum untuk observability dan komunikasi harus dijaga seminimal mungkin agar tidak memicu rebuild semua layanan terlalu sering
- Observability harus diadopsi sejak awal: mulai dari alat logging dasar seperti log JSON terstruktur dan correlation ID
- Kesimpulannya, saat memilih menerima kompleksitas, yang penting adalah merancang sistem yang tetap bisa dikelola dengan disiplin penuh
Kesimpulan
- Adopsi microservices secara tergesa-gesa hanya menambah beban, jadi kesederhanaan harus menjadi prioritas utama
- Jangan memisahkan tanpa pain point yang jelas; yang penting adalah menambahkan kompleksitas minimum yang diperlukan untuk bertahan dan tumbuh
- Bertahan hidup dulu, scaling belakangan
10 komentar
Saya secara umum setuju dengan isi tulisan aslinya.
Saya rasa ini adalah masalah pengalaman dalam organisasi.
Coba bayangkan berjualan makanan dari food truck lalu berkembang menjadi restoran.
Sejak awal, pengalaman para pemangku kepentingan benar-benar belum cukup untuk mempertimbangkan pembagian kerja dan spesialisasi.
Menurut saya, startup harus memilih cara yang berbiaya rendah untuk memperpanjang masa bertahan hidup. Microservices sama sekali tidak murah. Saat benar-benar diterapkan di lapangan, pendekatan ini menimbulkan biaya yang cukup besar. Sebisa mungkin, merancang arsitektur yang sesuai dengan layanan perusahaan sendiri adalah cara untuk mendapatkan efek serupa dengan biaya yang lebih rendah.
Bukan berarti microservices itu buruk. Ini adalah model yang membutuhkan biaya besar.
Menurut saya, cukup punya dua saja: monolitik khusus sinkron dan monolitik khusus asinkron... Saya melihat penerapan microservices pada akhirnya bergantung pada skala tabel yang harus dikelola di DB. Jika jumlah tabelnya sangat banyak dan kompleks, barulah perlu mempertimbangkan MSA; kalau sederhana, monolitik adalah pilihan yang paling pas.
Ketika semua gelombang ini telah berlalu, bagaimana generasi mendatang akan mengingat era ini?
Saat itu pun ada gelombangnya sendiri...
Saya juga berpikir microservice punya banyak kelebihan di startup. Pertama, saya benar-benar merekomendasikan kelebihan menggunakan monorepo.
Saya setuju bahwa di era pengembangan AI saat ini, menerapkan sistem dalam unit-unit kecil dengan tanggung jawab tunggal adalah hal yang esensial.
Ini sempat sedikit muncul di kolom opini juga, tetapi ekosistem beam/otp memang terasa cukup fleksibel dan bagus. Dalam kasus Gleam, sintaks bagus dari Go dan Rust dipadukan dengan stabilitas beam, sehingga menjadi bahasa yang cukup mengesankan. Sepertinya saya ingin mulai mencobanya pelan-pelan untuk proyek skala kecil.
Kalau tim dipecah-pecah sembarangan, bahkan sekadar berkumpul dan bertukar pendapat pun jadi pekerjaan yang sangat besar.
Opini Hacker News