Aplikasi biasanya tidak menjadi rumit dalam semalam. Kompleksitas tumbuh perlahan setiap kali fitur baru ditambahkan, integrasi bertambah, developer bergabung, dan data semakin besar.
Masalahnya, keputusan teknis yang baik untuk 1.000 pengguna belum tentu cocok ketika sistem melayani satu juta pengguna.
Itulah mengapa Cara Mendesain Software Architecture perlu mempertimbangkan kemampuan sistem untuk berubah.
Tujuan utamanya bukan membangun arsitektur paling canggih, tetapi menciptakan sistem yang mudah dimodifikasi, dapat diukur, tahan terhadap kegagalan, dan tidak menghambat bisnis ketika skalanya meningkat.
Tentukan Architectural Characteristics yang Paling Penting
Tidak semua aplikasi membutuhkan karakteristik arsitektur yang sama.
Platform pembayaran mungkin sangat memprioritaskan security, data consistency, dan availability. Sebaliknya, platform streaming bisa memberikan perhatian lebih besar pada throughput dan latency.
AWS Well-Architected Framework menggunakan enam perspektif utama, yaitu operational excellence, security, reliability, performance efficiency, cost optimization, dan sustainability.
Artinya, arsitektur selalu melibatkan trade-off.
Mengejar availability mendekati sempurna dapat meningkatkan biaya secara signifikan. Google Cloud bahkan menyarankan organisasi menentukan target reliability yang realistis berdasarkan pengalaman pengguna, bukan otomatis mengejar 100%.
Pilih tiga atau empat karakteristik paling penting berdasarkan bisnis. Keputusan ini akan membantu menentukan database, deployment strategy, redundancy, caching, sampai pola komunikasi antarkomponen.
Pisahkan Domain agar Kompleksitas Tetap Terkendali
Ketika aplikasi kecil, menempatkan banyak fungsi dalam satu service masih mudah dikelola.
Masalah mulai terasa ketika ribuan fungsi saling bergantung.
Domain-driven design dapat membantu tim membagi sistem berdasarkan area bisnis. Martin Fowler menjelaskan bahwa Domain-Driven Design berpusat pada model domain yang memahami proses dan aturan bisnis, terutama ketika domain memiliki logika yang kompleks.
Misalnya sistem fintech dapat dipisahkan menjadi domain Account, Transaction, Loan, Fraud, dan Notification.
Pemisahan ini tidak berarti semuanya harus menjadi microservice.
Monolith modular pun dapat menjadi pilihan bagus selama boundary jelas.
Tujuan utamanya adalah membatasi kompleksitas sehingga developer tidak perlu memahami seluruh sistem setiap kali mengubah satu fitur.
Rancang untuk Perubahan, Bukan untuk Prediksi Sempurna
Tidak ada tim yang benar-benar mengetahui bagaimana produk akan berkembang lima tahun ke depan.
Karena itu, over-engineering justru bisa menjadi jebakan.
Sistem kecil mungkin hanya membutuhkan aplikasi modular dan satu database. Ketika traffic atau organisasi berkembang, barulah komponen tertentu dipisahkan.
Martin Fowler menekankan bahwa arsitektur yang baik mendukung evolusinya sendiri dan berkaitan erat dengan proses pengembangan software.
Prinsip ini membuat tim fokus pada evolvability.
Gunakan abstraction pada area yang memang sering berubah, tetapi jangan membuat lima lapisan abstraksi hanya untuk kemungkinan yang belum jelas.
Misalnya, jika bisnis baru menggunakan satu payment gateway dan belum ada rencana konkret menambah provider lain, hindari membangun platform pembayaran generik yang sangat kompleks.
Sediakan struktur yang mudah direfactor ketika kebutuhan tersebut benar-benar muncul.
Buat Sistem yang Mudah Di-scale Secara Bertahap
Ketika pengguna meningkat sepuluh kali lipat, idealnya tim tidak harus mengganti seluruh arsitektur.
Mulailah dengan memahami pola workload.
Apakah bottleneck berada di application server, database, storage, network, atau third-party service?
Microsoft menjelaskan bahwa scalability dapat dibatasi oleh bottleneck dan titik sinkronisasi dalam sistem. Horizontal scaling bekerja lebih efektif apabila aplikasi dirancang untuk menambah instance tanpa koordinasi berlebihan.
Pendekatan stateless sangat membantu di sini.
Jika session pengguna hanya tersimpan di memory satu server, penambahan instance menjadi lebih rumit. Simpan state penting di database, distributed cache, atau persistent storage.
Selain itu, gunakan asynchronous processing untuk pekerjaan yang tidak harus selesai saat request berlangsung.
Misalnya proses generate laporan besar dapat masuk ke queue dan diproses worker sehingga pengguna tidak menunggu request selama beberapa menit.
Desain semacam ini meningkatkan skalabiltas tanpa langsung menambah kompleksitas ekstrem.
Jangan Mengabaikan Database Architecture
Banyak sistem terlihat scalable pada application layer tetapi akhirnya terhambat oleh database.
Database sering menjadi shared resource yang digunakan hampir semua fitur.
Optimasi sederhana seperti indexing, query analysis, caching, read replica, atau partitioning dapat memberikan dampak lebih besar daripada memecah aplikasi menjadi banyak service.
Pada skala tertentu, batas data juga perlu mengikuti batas domain.
Modul Order, misalnya, sebaiknya mempunyai ownership yang jelas terhadap data pesanan. Modul lain tidak bebas melakukan perubahan langsung terhadap tabel tersebut.
Google Cloud merekomendasikan desain modular dan interface yang jelas karena dapat membantu scaling komponen secara independen.
Dengan ownership data yang lebih terkontrol, pemisahan komponen pada masa depan menjadi lebih mudah.
Tanpa aturan tersebut, perubahan schema sederhana dapat menimbulkan efek samping ke banyak bagian sistem.
Otomatiskan Testing, Deployment, dan Konfigurasi
Pertumbuhan software bukan hanya persoalan traffic.
Jumlah developer dan frekuensi perubahan kode juga meningkat.
Jika setiap deployment membutuhkan checklist manual sepanjang dua halaman, proses release akan semakin lambat ketika produk berkembang.
Gunakan automated test, CI/CD, infrastructure as code, dan automated deployment sejak ukuran tim masih masuk akal.
AWS merekomendasikan automation sebagai bagian dari desain cloud karena memungkinkan workload direplikasi dan diubah tanpa terlalu bergantung pada pekerjaan manual.
Automated testing juga membantu developer melakukan refactoring dengan lebih percaya diri.
Konfigruasi environment sebaiknya dapat direproduksi dengan jelas agar perbedaan development, staging, dan production tidak menjadi sumber bug.
Dengan automation yang sehat, menambah developer tidak otomatis membuat proses delivery semakin lambat.
Gunakan Data untuk Mengevaluasi Arsitektur
Jangan melakukan perubahan besar berdasarkan perasaan semata.
Tambahkan metrics, logs, tracing, dan monitoring untuk mengetahui perilaku sistem di production.
Pantau p95 atau p99 latency, error rate, CPU, memory, database connection, cache hit rate, queue backlog, dan throughput sesuai karakteristik produk.
Google Cloud menempatkan observability sebagai salah satu prinsip utama reliability karena monitoring membantu tim mengenali tren dan potensi kegagalan lebih cepat.
Informasi ini juga membantu menghindari solusi yang salah.
Misalnya tim mengira aplikasi lambat karena monolith terlalu besar. Setelah tracing dilakukan, ternyata 70% waktu request habis menunggu API eksternal.
Dalam kasus seperti itu, migrasi ke microservices tidak menyelesaikan penyebab utama.
Observabilty mengubah keputusan arsitektur dari opini menjadi keputusan berbasis data.
Dokumentasikan Keputusan dan Trade-off Arsitektur
Developer baru sering melihat kode dan bertanya, “Kenapa sistem dibuat seperti ini?”
Tanpa dokumentasi, jawaban yang tersisa biasanya hanya, “Dulu memang dibuat begitu.”
Gunakan Architecture Decision Record untuk mendokumentasikan keputusan penting seperti pilihan database, messaging system, caching strategy, atau service boundary.
Martin Fowler menjelaskan bahwa ADR menyimpan keputusan, konteks, alternatif, trade-off, serta konsekuensinya sehingga tim dapat memahami alasan desain bahkan bertahun-tahun kemudian.
Dokumentasi semacam ini juga memudahkan evaluasi ulang.
Jika asumsi bisnis berubah, tim dapat melihat alasan keputusan lama dan menentukan apakah keputusan tersebut masih relevan.
Arsitektur akhirnya menjadi proses pembelajaran yang terus berlangsung, bukan sekadar diagram yang dibuat pada awal proyek lalu terlupakan setelah beberapa perubhaan.
Cara Mendesain Software Architecture yang tahan terhadap pertumbuhan membutuhkan keseimbangan antara simplicity, modularity, scalability, reliability, dan maintainability.
Hindari desain berlebihan berdasarkan prediksi yang belum pasti. Bangun sistem yang mudah diamati dan diubah, kemudian gunakan data production untuk menentukan langkah berikutnya.
Evaluasi arsitektur secara berkala agar teknologi selalu mendukung pertumbuhan bisnis, bukan justru menghambatnya.