Kapan proyek perlu menyederhanakan arsitektur atau ditutup? Jawaban singkatnya: ketika biaya mental dan operasional untuk mempertahankan sistem mulai lebih besar daripada nilai yang benar-benar bisa dikirim. Tanda-tandanya biasanya bukan satu bug besar, melainkan akumulasi kecil: release makin lambat, perubahan sederhana butuh menyentuh banyak lapisan, hanya satu atau dua orang yang paham sistem, dan tooling mulai lebih sering dilayani daripada membantu delivery.

Refleksi ini relevan untuk banyak proyek open source maupun internal product. Kisah penutupan Fornjot sering dijadikan pemicu berpikir bukan karena dramanya, tetapi karena ia menunjukkan pola yang umum dalam rekayasa software: ambisi arsitektur bisa tumbuh lebih cepat daripada kapasitas maintainer. Artikel ini membahas cara menilai apakah proyek sebaiknya mempertahankan arsitektur saat ini, menyederhanakannya, mengecilkan scope, atau menghentikannya secara sadar dan bertanggung jawab.

Mengapa proyek yang "bagus secara teknis" tetap bisa gagal dipertahankan

Banyak tim menganggap masalah utama proyek adalah kualitas implementasi. Padahal, cukup banyak proyek runtuh bukan karena kodenya buruk, melainkan karena biaya total pemeliharaan tidak lagi sebanding dengan manfaatnya.

Beberapa penyebab umum:

  • Arsitektur terlalu ambisius untuk ukuran tim. Sistem modular, plugin-heavy, event-driven, atau highly extensible memang fleksibel, tetapi setiap titik ekstensi menambah kontrak yang harus dijaga.
  • Tooling menumpuk. CI kompleks, generator kode, custom build pipeline, banyak environment, matrix testing, dan linting berlapis bisa memperlambat kontribusi.
  • Bus factor rendah. Jika hanya satu maintainer memahami dependency graph, proses release, dan area kritis, proyek rapuh meskipun desainnya elegan.
  • Scope produk kabur. Tim terus membangun fondasi untuk kemungkinan masa depan, sementara use case inti belum stabil atau belum tervalidasi.
  • Biaya perubahan terlalu tinggi. Fitur kecil memerlukan update di banyak package, adapter, interface, migration, dan dokumentasi lintas modul.

Masalah-masalah ini sering tidak terlihat dari luar. Repository tampak rapi, test suite hijau, dan struktur paket terpisah dengan baik. Namun dari dalam, setiap perubahan bisa terasa seperti menggerakkan banyak roda sekaligus.

Empat opsi keputusan: pertahankan, sederhanakan, perkecil scope, atau tutup

Keputusan terbaik jarang hanya dua pilihan. Daripada berpikir "lanjut atau berhenti", lebih berguna memakai empat mode keputusan berikut.

1. Pertahankan arsitektur saat ini

Pilih ini jika arsitektur yang ada memang mendukung kebutuhan nyata dan tim masih mampu mengoperasikannya.

Cocok jika:

  • Banyak modul benar-benar dipakai dan punya batas tanggung jawab yang jelas.
  • Onboarding kontributor baru masih masuk akal.
  • Release cadence stabil.
  • Insiden operasional rendah dan debugging tidak terlalu mahal.
  • Tim punya kapasitas untuk menjaga kontrak antar komponen.

2. Sederhanakan arsitektur

Ini pilihan paling sering masuk akal untuk tim kecil. Tujuannya bukan "mengurangi kualitas", tetapi mengurangi permukaan kompleksitas.

Contoh penyederhanaan:

  • Menggabungkan package internal yang selalu berubah bersama.
  • Menghapus abstraction layer yang hanya punya satu implementasi.
  • Mengurangi plugin point yang tidak pernah dipakai pihak ketiga.
  • Mengganti orkestrasi async kompleks dengan alur sinkron yang lebih mudah dilacak, jika skala masih memungkinkan.
  • Menyatukan pipeline build/test yang terpecah tanpa manfaat kuat.

3. Perkecil scope produk

Kadang masalah utama bukan bentuk arsitekturnya, melainkan target produknya terlalu luas. Dalam kasus ini, yang dikurangi adalah area masalah, bukan sekadar lapisan teknis.

Contoh:

  • Mendukung satu platform dulu, bukan tiga platform sekaligus.
  • Menetapkan satu workflow inti sebagai fokus, bukan banyak mode penggunaan.
  • Menghapus fitur eksperimen yang mahal dirawat tetapi sedikit dipakai.
  • Menyatakan beberapa integrasi sebagai di luar scope resmi.

4. Tutup proyek

Menutup proyek bukan selalu kegagalan. Kadang itu keputusan engineering yang paling jujur jika:

  • Nilai pengguna tidak sebanding dengan beban maintainability.
  • Tidak ada kapasitas maintainer yang realistis dalam jangka menengah.
  • Arsitektur tidak bisa disederhanakan tanpa menghapus alasan utama proyek itu ada.
  • Proyek terus menyedot energi dari prioritas lain yang lebih bernilai.

Keputusan menghentikan proyek sering lebih sehat daripada mempertahankan ilusi keberlanjutan. Proyek yang tampak hidup tetapi tidak benar-benar bisa dipelihara akan membebani pengguna, kontributor, dan maintainer.

Framework keputusan praktis untuk tim engineering

Berikut kerangka evaluasi yang bisa dipakai pada proyek internal maupun open source. Fokusnya adalah membandingkan nilai yang dikirim dengan kompleksitas yang harus ditanggung.

Langkah 1: Petakan nilai inti proyek

Tuliskan dengan spesifik:

  • Masalah utama apa yang diselesaikan proyek?
  • Siapa pengguna aktifnya?
  • Fitur atau komponen mana yang benar-benar membuat proyek ini bernilai?
  • Bagian mana yang hanya "mungkin berguna nanti"?

Jika tim sulit menjawab nilai inti tanpa jargon arsitektur, itu sinyal bahwa proyek mungkin terlalu berfokus pada mekanisme internal.

Langkah 2: Hitung biaya kompleksitas, bukan hanya biaya infrastruktur

Banyak tim hanya menghitung biaya server, storage, atau CI minutes. Padahal biaya terbesar sering ada di sisi manusia:

  • Waktu memahami struktur kode.
  • Waktu review perubahan kecil.
  • Waktu sinkronisasi lintas modul.
  • Waktu debugging dependency dan integrasi.
  • Energi maintainer untuk menjawab issue, menjaga kompatibilitas, dan merawat tooling.

Pertanyaan pentingnya bukan "apakah ini arsitektur yang bagus?" tetapi "apakah tim kita mampu membayar biaya perubahannya secara terus-menerus?"

Langkah 3: Ukur rasio perubahan terhadap gesekan

Ambil 5-10 perubahan terakhir, lalu audit:

  • Berapa file atau package yang disentuh per perubahan?
  • Apakah perubahan kecil sering memerlukan refactor kontrak publik?
  • Berapa lama dari coding sampai merge atau release?
  • Apakah kegagalan sering muncul di integration boundary?

Jika fitur sederhana selalu menyentuh banyak lapisan, arsitektur kemungkinan tidak proporsional terhadap kebutuhan saat ini.

Langkah 4: Evaluasi bus factor dan kapasitas maintainer

Tim kecil harus jujur soal kapasitas. Arsitektur modular yang indah di atas kertas bisa menjadi liabilitas jika hanya satu orang memahami bagaimana modul saling berinteraksi.

Tanyakan:

  • Jika maintainer utama cuti sebulan, siapa yang bisa release?
  • Siapa yang paham proses build, dependency graph, dan area performa sensitif?
  • Apakah dokumentasi cukup untuk contributor baru memperbaiki bug non-trivial?

Jika jawaban mayoritas adalah satu nama yang sama, proyek berada di zona rawan.

Langkah 5: Putuskan berdasarkan tindakan yang bisa dieksekusi

Hasil evaluasi harus berujung pada keputusan operasional yang jelas, misalnya:

  • Pertahankan: tidak ada perubahan struktur besar, fokus delivery.
  • Sederhanakan: gabungkan modul A/B/C dalam satu codebase, hapus extension point X, kurangi matrix CI.
  • Perkecil scope: hentikan dukungan fitur Y dan targetkan hanya use case Z.
  • Tutup: freeze repo, dokumentasikan status, arsipkan roadmap, dan beri migrasi alternatif bila memungkinkan.

Sinyal peringatan bahwa arsitektur mulai terlalu mahal

1. Tooling lebih sering dibahas daripada fitur inti

Jika diskusi engineering didominasi oleh build orchestration, workspace layout, code generation, compatibility layer, atau plugin contract, sementara use case pengguna jarang bergerak, ada kemungkinan kompleksitas internal mengambil alih fokus.

2. Modularitas tidak menghasilkan independensi nyata

Secara teori, modul terpisah memudahkan evolusi. Dalam praktik, banyak proyek memiliki modul yang selalu berubah bersama. Jika package A, B, dan C hampir selalu dirilis bersamaan, pemisahan itu mungkin hanya memindahkan kompleksitas, bukan menguranginya.

3. Satu fitur kecil memerlukan banyak koordinasi

Misalnya, menambah satu field baru ke alur bisnis memerlukan perubahan pada domain model, event schema, adapter, API, UI state, test snapshot, migration, dan dokumentasi plugin. Itu tidak selalu salah, tetapi bila terlalu sering terjadi untuk perubahan kecil, struktur sistem mungkin terlalu berlapis.

4. Onboarding lambat meskipun dokumentasi ada

Dokumentasi yang baik tidak selalu cukup jika model mental sistem terlalu rumit. Bila engineer baru tetap butuh waktu lama untuk melakukan perubahan aman, penyebabnya sering ada pada desain interaksi antar bagian.

5. Maintainer lelah mengelola kompatibilitas

Semakin banyak public interface, plugin API, format data, atau internal contract yang dianggap stabil, semakin berat beban backward compatibility. Ini sering tidak terasa di awal, tetapi menjadi mahal seiring waktu.

6. Scope berkembang lebih cepat daripada validasi penggunaan

Fitur dan extension point bertambah untuk kemungkinan masa depan, bukan untuk kebutuhan yang sudah terbukti. Ini pola umum over-engineering: fondasi makin megah, tetapi jalan utama belum banyak dilewati.

Tabel trade-off: monolit vs modular/plugin-heavy

Tidak ada pendekatan yang selalu benar. Yang penting adalah kecocokannya terhadap ukuran tim, stabilitas domain, dan kebutuhan ekstensi.

AspekMonolit SederhanaModular/Plugin-Heavy
Kecepatan awal deliveryTinggi, karena alur perubahan langsungLebih lambat, karena perlu kontrak dan boundary
Kemudahan refactor lintas komponenBiasanya lebih mudah jika tim kecilBisa sulit jika kompatibilitas antar modul harus dijaga
Ekstensi pihak ketigaTerbatasLebih baik jika plugin API stabil dan benar-benar dipakai
Beban toolingRelatif rendahSering lebih tinggi: build, versioning, compatibility testing
Bus factorBisa lebih aman bila struktur mudah dipahamiSering lebih berisiko jika hanya sedikit orang paham boundary
Isolasi tanggung jawabBisa kabur jika disiplin lemahLebih jelas secara desain, tetapi lebih mahal dijaga
Skala organisasiCocok untuk tim kecil hingga menengahLebih cocok jika ada banyak kontributor atau kebutuhan ekstensi nyata
Biaya perubahan kecilSering lebih rendahSering lebih tinggi karena banyak titik integrasi
Risiko over-engineeringAda, tetapi lebih terlihatTinggi jika extensibility dibangun terlalu dini

Kapan memilih monolit sederhana? Saat domain belum stabil, tim kecil, dan prioritas utama adalah belajar cepat serta mengirim fitur inti.

Kapan modular/plugin-heavy masuk akal? Saat ada kebutuhan ekstensi yang nyata, boundary domain relatif matang, dan kapasitas maintainer cukup untuk menjaga kontrak antar komponen dalam jangka panjang.

Checklist audit maintainability untuk tim kecil

Gunakan checklist ini setiap kuartal atau sebelum memulai refactor besar.

A. Struktur kode dan boundary

  • Apakah setiap modul punya alasan eksistensi yang jelas, bukan sekadar "biar rapi"?
  • Apakah modul-modul tertentu hampir selalu berubah bersama?
  • Apakah ada abstraction layer yang hanya memiliki satu implementasi tanpa kebutuhan substitusi nyata?
  • Apakah dependency direction konsisten dan mudah dijelaskan?
  • Apakah fitur inti bisa dipahami tanpa membaca seluruh codebase?

B. Delivery dan perubahan

  • Apakah bug fix kecil bisa dirilis tanpa koordinasi besar?
  • Apakah pipeline build/test cukup cepat untuk loop feedback yang sehat?
  • Apakah engineer tahu area mana yang harus disentuh untuk perubahan umum?
  • Apakah review sering tertahan karena struktur terlalu kompleks?
  • Apakah perubahan lintas modul benar-benar sering dibutuhkan?

C. Tooling dan operasi

  • Apakah ada tool internal yang hanya dipahami satu orang?
  • Apakah CI punya job yang mahal tetapi jarang memberi sinyal berguna?
  • Apakah proses release terdokumentasi dan bisa dijalankan orang lain?
  • Apakah local setup untuk contributor baru masuk akal?
  • Apakah observability cukup untuk tracing kegagalan tanpa ritual manual yang rumit?

D. Tim dan keberlanjutan

  • Siapa yang bisa mengambil alih jika maintainer utama tidak tersedia?
  • Apakah dokumentasi arsitektur menjelaskan keputusan, bukan hanya struktur folder?
  • Apakah ada area kritis tanpa owner cadangan?
  • Apakah jumlah issue, PR, dan permintaan pengguna sesuai kapasitas tim?
  • Apakah roadmap masih realistis terhadap energi maintainer?

E. Produk dan scope

  • Apakah fitur yang paling mahal dirawat juga yang paling bernilai bagi pengguna?
  • Apakah ada mode penggunaan resmi yang sebenarnya hampir tidak dipakai?
  • Apakah proyek masih menyelesaikan masalah inti dengan baik?
  • Apakah scope bertambah karena kebutuhan nyata atau karena dorongan teknis internal?

Jika banyak jawaban negatif terkumpul pada area yang sama, itu petunjuk prioritas tindakan. Jangan jadikan audit ini sekadar dokumen; ia harus menghasilkan daftar penyederhanaan yang konkret.

Contoh keputusan arsitektur yang bisa disederhanakan

Terkadang tim tahu ada masalah, tetapi bingung mulai dari mana. Berikut beberapa intervensi yang biasanya memberi dampak besar.

Gabungkan modul yang selalu berubah bersama

Jika beberapa package internal punya release cycle yang sama dan jarang digunakan terpisah, gabungkan dulu. Ini mengurangi versioning overhead, compatibility friction, dan koordinasi review.

Turunkan level genericity

Hapus interface atau adapter yang dibuat untuk kemungkinan masa depan tetapi tidak dipakai. Generic design bernilai jika ada variasi nyata. Kalau belum ada, abstraksi itu hanya menambah jarak antara masalah dan solusi.

Batasi extension point

Plugin architecture masuk akal jika ada plugin author atau kebutuhan customization yang konsisten. Jika tidak, lebih aman membuat API internal yang boleh berubah, lalu menstabilkannya nanti ketika pola penggunaan sudah jelas.

Sederhanakan pipeline engineering

Kurangi matrix testing yang tidak kritis, satukan script build, hilangkan langkah manual yang bisa didokumentasikan ulang, dan prioritaskan feedback cepat pada jalur perubahan umum.

Bekukan fitur eksperimental

Daripada merawat banyak cabang arah produk, pilih satu jalur utama. Fitur eksperimental boleh tetap ada, tetapi secara eksplisit dinyatakan tidak stabil atau di luar dukungan utama.

Contoh format audit keputusan dalam repository

Agar evaluasi tidak berhenti di diskusi, simpan keputusan dalam dokumen sederhana yang bisa direview tim.

Keputusan: Sederhanakan arsitektur dalam 2 iterasi berikutnya

Masalah utama:
- Perubahan kecil sering menyentuh 4-6 modul
- Hanya 1 maintainer paham proses release penuh
- Pipeline CI lambat dan sering gagal di integration boundary

Nilai yang harus dipertahankan:
- Workflow inti pengguna
- API publik yang aktif dipakai
- Kualitas test pada domain inti

Yang akan disederhanakan:
- Gabungkan package internal A, B, C
- Hapus plugin hook yang belum pernah dipakai
- Kurangi target platform dari 3 menjadi 1 target resmi
- Ringkas pipeline CI menjadi jalur cepat + jalur lengkap terjadwal

Risiko:
- Refactor awal memperlambat delivery 1-2 iterasi
- Beberapa integrasi non-inti tidak lagi didukung

Kriteria berhasil:
- Bug fix umum cukup menyentuh 1-2 area kode
- Release dapat dilakukan oleh lebih dari 1 engineer
- Waktu review dan integrasi menurun secara nyata

Format seperti ini membantu tim membedakan antara niat dan komitmen operasional.

Kapan proyek sebaiknya ditutup, bukan diperbaiki lagi

Ada kondisi ketika refactor tambahan justru memperpanjang biaya tanpa mengubah kenyataan dasar.

Pertimbangkan penutupan jika:

  • Tidak ada maintainer berkelanjutan. Bukan sekadar sibuk minggu ini, tetapi memang tidak ada kapasitas realistis ke depan.
  • Use case inti tidak tervalidasi. Setelah cukup waktu, proyek belum menemukan pengguna atau kebutuhan yang stabil.
  • Arsitektur inti dan tujuan produk bertabrakan. Untuk membuat proyek berkelanjutan, Anda harus menghapus karakter utama yang menjadi alasan proyek itu dibuat.
  • Biaya emosional maintainer terlalu tinggi. Burnout adalah biaya engineering yang nyata.
  • Alternatif lain sudah lebih layak. Kadang ekosistem sudah punya solusi lebih sehat untuk pengguna.

Jika memilih menutup, lakukan dengan disiplin:

  • Jelaskan status proyek secara terbuka.
  • Dokumentasikan alasan teknis dan operasionalnya.
  • Tandai area yang masih berguna untuk dipelajari atau diambil ulang.
  • Jika memungkinkan, arahkan pengguna ke alternatif atau strategi migrasi.
  • Arsipkan roadmap yang tidak lagi aktif agar ekspektasi jelas.

Penutupan yang jujur jauh lebih bermanfaat daripada membiarkan proyek tampak aktif tetapi tidak benar-benar aman digunakan atau dikontribusikan.

Kesalahan umum saat mengevaluasi proyek

  • Menganggap kompleksitas selalu tanda kematangan. Kompleksitas bisa jadi hanya utang koordinasi yang belum terasa penuh.
  • Menilai arsitektur dari diagram, bukan dari biaya perubahan. Diagram bisa bersih, tetapi workflow engineering tetap menyakitkan.
  • Mengabaikan kapasitas maintainer. Desain yang cocok untuk organisasi besar belum tentu cocok untuk satu atau dua orang.
  • Mempertahankan semua compatibility point. Tidak semua kontrak layak dijaga selamanya.
  • Menunda keputusan karena sunk cost. Banyak investasi masa lalu tidak otomatis membenarkan biaya masa depan.

Penutup

Kapan proyek perlu menyederhanakan arsitektur atau ditutup pada akhirnya adalah pertanyaan tentang keberlanjutan engineering, bukan gengsi teknis. Arsitektur yang baik bukan yang paling modular, paling abstrak, atau paling extensible, melainkan yang memungkinkan tim mengirim nilai dengan beban yang masih mampu mereka tanggung.

Jika tim kecil mulai tertahan oleh tooling, boundary, kompatibilitas, dan bus factor, langkah paling dewasa sering bukan menambah lapisan baru, tetapi mengurangi permukaan masalah. Sederhanakan ketika struktur sudah terlalu mahal, perkecil scope ketika target terlalu luas, dan tutup proyek ketika keberlanjutan sudah tidak realistis. Keputusan yang jujur biasanya lebih murah daripada mempertahankan kompleksitas yang tidak lagi membayar dirinya sendiri.