Layered Architecture vs Clean Architecture: Perbandingan
Layered Architecture dan Clean Architecture sering dibandingkan seolah-olah keduanya adalah dua pilihan yang sepenuhnya berbeda. Keduanya memang sama-sama membagi aplikasi ke dalam bagian-bagian yang lebih kecil, tetapi fokusnya berbeda.
Layered Architecture terutama membantu tim mengatur tanggung jawab berdasarkan lapisan. Clean Architecture menambahkan aturan yang lebih tegas tentang boundary dan arah dependency agar aturan bisnis tidak bergantung pada database, framework, atau layanan eksternal.
Artikel ini membandingkan keduanya dengan contoh use case yang sama. Tujuannya bukan mencari pemenang, tetapi membantu kamu memilih tingkat struktur yang sesuai dengan umur, risiko, dan kompleksitas project.
Jawaban singkat: apa perbedaan utamanya?
| Aspek | Layered Architecture | Clean Architecture |
|---|---|---|
| Fokus | Memisahkan tanggung jawab berdasarkan layer | Melindungi business rules di boundary terdalam |
| Arah dependency | Sering mengikuti urutan layer dari atas ke bawah | Dependency source code mengarah ke dalam |
| Struktur | Biasanya lebih sederhana dan langsung | Lebih banyak port, adapter, dan boundary |
| Testing | Mudah dimulai, tetapi bisa ikut menyentuh infrastructure | Unit test use case dapat berjalan tanpa database atau framework |
| Cocok untuk | CRUD, aplikasi kecil, dan tim yang ingin bergerak cepat | Domain kompleks, integrasi banyak, dan aturan bisnis jangka panjang |
Clean Architecture bukan berarti tidak memiliki layer. Perbedaannya terletak pada aturan hubungan antar-layer. Aplikasi layered dapat menjadi sangat rapi, sementara aplikasi yang mengaku clean tetap bisa berantakan jika dependency dan tanggung jawabnya tidak dijaga.
Layered Architecture: susunan dan alurnya
Struktur layered yang umum terdiri dari Presentation, Application atau Service, Domain, dan Data atau Infrastructure. Nama layer dapat berbeda, tetapi idenya sama: setiap bagian memiliki tanggung jawab yang lebih sempit.
HTTP request
↓
Controller / Presentation
↓
Application Service
↓
Repository / Data Access
↓
Database atau layanan eksternal
Misalnya pada fitur membuat pesanan, controller membaca request dan memanggil OrderService. Service memvalidasi input, menghitung total, lalu memanggil repository untuk menyimpan pesanan. Repository menerjemahkan operasi itu ke query database.
Pendekatan ini mudah dipahami karena alurnya mengikuti cara request berjalan. Untuk aplikasi CRUD, pembagian tersebut sering sudah cukup. Developer baru juga dapat menemukan tempat untuk menambah endpoint, validasi, dan query tanpa mempelajari terlalu banyak abstraksi.
Risikonya muncul ketika service mulai berisi terlalu banyak hal: aturan diskon, detail ORM, format response, pemanggilan payment gateway, dan pengiriman notifikasi. Secara nama masih ada layer, tetapi business logic sudah bergantung pada detail teknis. Perubahan database atau framework kemudian merambat ke banyak bagian.
Clean Architecture: boundary dan dependency ke dalam
Clean Architecture biasanya digambarkan sebagai lingkaran. Di tengah ada Entities atau domain rules. Di sekelilingnya terdapat Use Cases, Interface Adapters, lalu Frameworks and Drivers seperti database, web framework, dan layanan eksternal.
Aturan paling pentingnya adalah dependency source code mengarah ke dalam. Use case boleh mendefinisikan interface yang dibutuhkan, tetapi tidak mengimpor implementasi database atau framework. Implementasi di luar memenuhi interface tersebut.
HTTP Controller (adapter)
↓
CreateOrder Use Case
↓ menggunakan port/interface
Order Repository Adapter
↓
Database
Alur runtime tetap dapat bergerak dari luar ke dalam dan kembali ke luar. Yang dibedakan adalah arah dependency pada kode. CreateOrder mengetahui aturan membuat pesanan dan kontrak repository, tetapi tidak perlu tahu apakah data disimpan di PostgreSQL, API pihak ketiga, atau in-memory store untuk test.
Boundary ini membuat aturan bisnis lebih mudah diuji secara terisolasi. Sebagai konsekuensinya, tim perlu menulis interface, adapter, dan wiring dependency. Tambahan tersebut layak jika bagian inti sering berubah, mahal untuk rusak, atau harus dipakai oleh lebih dari satu delivery mechanism.
Contoh use case: membuat pesanan
Bayangkan aturan berikut: pelanggan tidak boleh membuat pesanan kosong, stok harus cukup, diskon hanya berlaku untuk pelanggan yang memenuhi syarat, dan pembayaran harus dibuat setelah total tervalidasi.
Dengan Layered Architecture
OrderController menerima request lalu memanggil OrderService. Service memuat produk melalui ProductRepository, menjalankan validasi, menghitung total, menyimpan order, lalu memanggil payment client.
Controller → OrderService → ProductRepository → Database
↘ PaymentClient
Model ini praktis. Namun jika OrderService langsung mengandalkan ORM dan SDK payment, test-nya membutuhkan banyak mock detail teknis. Ketika payment provider diganti, service juga perlu diubah.
Dengan Clean Architecture
CreateOrder menjadi use case yang hanya bergantung pada port seperti ProductReader, OrderWriter, dan PaymentGateway. Controller mengubah HTTP request menjadi input use case. Adapter database dan payment mengimplementasikan port tersebut.
HTTP Adapter → CreateOrder → ProductReader
→ OrderWriter
→ PaymentGateway
Unit test dapat memberikan fake untuk ketiga port tersebut. Test lalu fokus pada aturan stok, diskon, dan urutan pembayaran tanpa menyalakan database atau mengirim request ke payment provider. Harga yang harus dibayar adalah lebih banyak wiring dan file.
Trade-off yang perlu dipertimbangkan
Kecepatan awal versus biaya perubahan
Layered biasanya lebih cepat dibuat. Ini penting saat produk masih mencari bentuk dan sebagian besar pekerjaan berupa CRUD. Clean Architecture memerlukan keputusan boundary lebih awal, sehingga biaya awalnya lebih tinggi.
Sebaliknya, Clean Architecture dapat mengurangi biaya ketika aturan domain makin kompleks atau integrasi sering diganti. Abstraksi tidak otomatis menghasilkan desain baik; ia berguna ketika melindungi keputusan yang memang mahal untuk berubah.
Kesederhanaan versus isolasi testing
Layered dengan service dan repository konkret mudah diikuti. Namun test dapat menjadi integration test besar karena banyak detail ikut aktif. Clean memisahkan use case dari detail sehingga unit test lebih cepat, tetapi tim harus menjaga kontrak port agar tidak menjadi abstraksi kosong.
Fleksibilitas versus beban kognitif
Clean Architecture cocok ketika aplikasi memiliki lebih dari satu adapter, misalnya HTTP API, worker, dan command line. Untuk aplikasi kecil dengan satu database dan satu delivery mechanism, banyak boundary dapat membuat developer mencari-cari kode yang sebenarnya sederhana.
Kapan memilih Layered Architecture?
Pilih layered ketika:
- sebagian besar fitur adalah CRUD dengan aturan bisnis ringan;
- tim kecil membutuhkan struktur yang mudah dipelajari;
- framework dan database kemungkinan besar bertahan cukup lama;
- kecepatan validasi produk lebih penting daripada fleksibilitas jangka panjang.
Tetapkan aturan sederhana sejak awal: controller tidak berisi query, service tidak mencampur response HTTP dengan aturan domain, dan repository tidak mengambil keputusan bisnis. Layered yang disiplin sering lebih sehat daripada Clean Architecture yang hanya menambah folder.
Kapan memilih Clean Architecture?
Clean Architecture lebih masuk akal ketika:
- aturan domain adalah sumber risiko utama;
- database, payment, messaging, atau provider eksternal mungkin diganti;
- use case harus diuji cepat tanpa infrastructure;
- aplikasi memiliki beberapa entry point atau adapter;
- beberapa tim perlu bekerja pada boundary yang jelas.
Kamu tidak harus memindahkan seluruh aplikasi sekaligus. Mulai dari use case yang paling sering berubah atau paling mahal ketika gagal, lalu ukur apakah boundary baru benar-benar membantu.
Migrasi bertahap dari layered ke boundary yang lebih bersih
- Catat aturan bisnis yang saat ini bercampur dengan controller, ORM, atau SDK.
- Tulis test pada perilaku penting sebelum memindahkan kode.
- Pindahkan aturan tersebut ke service atau use case yang tidak bergantung pada framework.
- Definisikan interface hanya untuk dependency yang perlu diganti atau diisolasi.
- Buat adapter di luar boundary dan rakit dependency di composition root.
- Hapus coupling lama setelah test dan observability menunjukkan alurnya aman.
Migrasi seperti ini membuat tim mendapat feedback dari perubahan kecil. Jangan membuat interface untuk setiap class hanya karena pola tersebut terlihat “lebih clean”. Setiap boundary perlu membayar biayanya dengan pengurangan coupling, test yang lebih baik, atau kemampuan mengganti detail.
Checklist keputusan
- Apakah aturan bisnis dapat diuji tanpa database?
- Apakah controller atau service sudah terlalu mengetahui detail framework?
- Apakah ada lebih dari satu adapter atau integrasi yang penting?
- Apakah perubahan provider eksternal sering terjadi?
- Apakah tim memahami dan mampu menjaga boundary yang akan dibuat?
- Apakah manfaat isolasi sepadan dengan tambahan interface dan wiring?
Kesimpulan
Layered Architecture membantu mengorganisasi tanggung jawab secara sederhana. Clean Architecture menambahkan batas dan arah dependency agar core business lebih terlindungi dari detail teknis.
Mulai dengan struktur yang bisa dipahami tim. Perketat boundary ketika aturan domain, testing, atau perubahan infrastructure benar-benar membutuhkannya. Untuk pendalaman, baca Hexagonal Architecture: Ports and Adapters dan Domain-Driven Design.
Artikel Terkait
Lanjutkan membaca topik yang masih satu konteks.
CQRS Pattern: Pisahkan Read dan Write untuk Sistem Skalabel
Gunakan CQRS untuk memisahkan read dan write model, meningkatkan skalabilitas, menyederhanakan query kompleks, dan memperjelas boundary.
NoSQL vs Relational: Memilih Database yang Tepat untuk Proyek Kamu
Kerangka praktis untuk memilih database relational atau NoSQL berdasarkan bentuk data, query, konsistensi, dan kebutuhan operasional.
Hexagonal Architecture: Memahami Ports dan Adapters
Pahami hexagonal architecture lewat ports, adapters, arah dependency, manfaat testing, contoh use case, trade-off, dan panduan implementasi praktis.
Event Sourcing: Membangun Sistem yang Dapat Diaudit
Pahami event sourcing lewat contoh praktis, event stream, projection, audit trail, trade-off, dan kapan pattern ini layak dipakai.