Skip to content

Saat Saya Berhenti Memisahkan Kode Berdasarkan Lapisan Teknis

Adityo Guni Waluyo

Commit d7f02b2 memperkenalkan aturan wajib vertical slice architecture dan 4-tier testing: setiap fitur dibangun end-to-end dalam satu iterasi, bukan layer-by-layer horizontal. Hasilnya development lebih cepat, bug tertangkap di layer murah via Testcontainers, dan isolasi fitur bersih tanpa efek samping.

Ringkasan

Awalnya gue kira pisah kode per layer itu rapi, eh pas fitur nambah malah pusing karena ubah DB dikit API bisa error. Sekarang pakai vertical slice jadi satu fitur ngumpul dari migrasi sampai frontend, lebih aman nggak merembet kemana-mana. Testingnya dibagi empat level pakai Testcontainers dan Playwright buat alur kritis, debuggingnya juga wajib urut biar nggak asal tebak.

Saat Saya Berhenti Memisahkan Kode Berdasarkan Lapisan Teknis

Commit d7f02b2 di repositori my-plan menambahkan tiga file baru di jalur claude/skills/init-rules/packs/universal/: vertical-slice.md, testing.md, dan debugging.md. Ini bukan sekadar dokumentasi opsional yang bisa diabaikan. File-file ini adalah aturan wajib untuk semua proyek di workspace itu. Saat pertama kali melihat commit ini, saya sempat bertanya-tanya kenapa aturan seketat ini perlu dipaksakan sejak awal proyek dibuat.

Dulu saya pikir, bukannya lebih rapi kalau semua repository dikumpul di satu folder, semua service di folder lain, dan semua controller ditempatkan di area terpisah? Pisah berdasarkan lapisan teknis itu terlihat sangat terstruktur di awal. Semuanya tampak tertata rapi di mata developer yang baru bergabung, seolah-olah kita sedang membangun fondasi yang kokoh dan mudah dipelihara.

Ternyata, pas fitur mulai bertambah, ilusi kerapian itu langsung runtuh. Saya pernah menghabiskan waktu berjam-jam cuma buat ngecek kenapa satu perubahan kecil di skema database tiba-tiba bikin endpoint API gagal, padahal secara logika bisnis seharusnya aman. Dependensinya menyebar ke mana-mana. Vertical slice membalik logika ini sepenuhnya. Satu fitur, misalnya "Create Order", punya semua kodenya bareng dalam satu iterasi — migrasi database, repository, service, handler, route, sampai komponen frontend. Jimmy Bogard menjelaskan bahwa tujuannya adalah meminimalkan coupling antar slice, tapi memaksimalkan coupling di dalam satu slice itu sendiri. Ketika ada perubahan requirement, saya cuma perlu menyentuh satu tempat tanpa takut merusak fitur lain yang kebetulan pakai layer yang sama.

Jebakan Arsitektur Berlapis Tradisional

Arsitektur berlapis tradisional sering kali berakhir jadi bentuk "ice-cream cone" dalam strategi testing. Kita malah punya banyak sekali end-to-end test yang lambat dan rapuh, sementara unit test-nya sedikit banget. Akibatnya, feedback loop jadi panjang dan bug baru ketahuan pas udah telat, biasanya saat proses review atau malah di lingkungan staging yang sudah sulit dilacak.

Kombinasi vertical slice dengan piramida testing yang benar mengubah dinamika ini secara drastis. Developer bisa kerja paralel tanpa konflik file yang aneh-aneh, karena setiap orang mengurusi slice fitur mereka masing-masing dari atas sampai bawah. Hasilnya, siklus development jadi lebih cepat dan isolasi masalah jauh lebih mudah dilakukan tanpa harus membongkar seluruh basis kode.

Empat Lapisan Testing yang Waras

File testing.md di commit itu menetapkan standar 4-tier yang tegas. Ini bukan sekadar teori arsitektur, tapi aturan eksekusi harian yang harus diikuti di setiap pull request.

Pertama, unit test menangani logika murni dengan target cakupan di atas 70 persen. Tes ini harus berjalan sangat cepat dan tidak bergantung pada infrastruktur eksternal apa pun, memastikan logika bisnis inti tetap solid.

Kedua, integration test wajib memakai Testcontainers untuk menyalakan container Docker asli, misalnya Postgres atau Redis. Aturan di testing.md sangat eksplisit: jangan pernah mengganti engine database asli dengan SQLite cuma buat tes, karena sintaks dan perilaku target engine itu berbeda. Testcontainers mengelola siklus hidup lewat Docker API, memakai dynamic ports via UseSetting, mengunci tag image kayak postgres:17, dan menerapkan pola IAsyncLifetime agar container otomatis hancur setelah tes selesai.

Proses ini memastikan lingkungan testing kita sedekat mungkin dengan produksi. Misalnya, saat menguji fitur pembayaran, kita tidak lagi mengandalkan mock repository yang mengembalikan data palsu. Kita benar-benar menjalankan instance Postgres di dalam Docker, menjalankan migrasi schema yang sama persis dengan produksi, lalu menjalankan query integrasi. Jika ada perbedaan sintaks antara SQLite dan Postgres, tes akan gagal di lingkungan lokal kita, bukan mengejutkan kita di pipeline deployment.

Ketiga, end-to-end test memakai Playwright, tapi dibatasi ketat cuma untuk 5 sampai 10 alur kritis saja. Kita nggak perlu mengotomatisasi setiap klik di aplikasi karena biaya pemeliharaannya terlalu tinggi dan tesnya jadi lambat.

Keempat, smoke test berjalan otomatis sebagai health check setelah deployment untuk memastikan lingkungan produksi benar-benar siap menerima trafik pengguna tanpa error tersembunyi.

Debugging yang Sistematis

File ketiga, debugging.md, mewajibkan penerapan keterampilan systematic-debugging. Saat ada masalah, langkahnya bukan menebak-nebak atau asal ganti kode. Kita mulai dari melihat log Docker Compose, lalu mengikuti alur yang ketat: reproduksi, isolasi, perbaiki, tes, dan akhirnya cegah agar masalah yang sama nggak terulang.

Langkah reproduksi dan isolasi ini sering diabaikan, padahal ini adalah kunci untuk nggak terjebak dalam perbaikan yang malah menciptakan bug baru di tempat lain. Skill ini mencegah kebiasaan buruk "coba-coba restart sampai errornya hilang". Setiap perbaikan harus disertai dengan tes baru yang menjamin bug tersebut tidak akan muncul lagi di masa depan.

Intinya, aturan di commit ini bukan tentang mengekang kreativitas developer. Ini tentang membangun pagar pengaman yang memungkinkan tim bergerak cepat tanpa takut merusak fitur lain. Saya awalnya condong ke struktur berlapis karena terbiasa dengan pola itu, tapi setelah melihat betapa seringnya perubahan kecil memicu efek domino, saya sadar bahwa mengelompokkan kode berdasarkan fitur adalah satu-satunya cara yang masuk akal untuk menjaga kecepatan tanpa mengorbankan stabilitas.

Sources

[1] https://martinfowler.com/articles/practical-test-pyramid.html
[2] https://www.jimmybogard.com/vertical-slice-architecture
[3] https://milanjovanovic.tech/blog/testcontainers-best-practices-dotnet-integration-testing
[4] https://devblogs.microsoft.com/ise/testing-with-testcontainers

Artikel terkait