Konsep Layered Architecture pada Software
Hi Teman2,
Kemaren kita sudah belajar dari building block paling dasar mengenai praktek pemrograman yang melibatkan satu komponen atau kelas atau object. Karena tidak semua bahasa pemrograman punya konsep kelas. Contohnya di golang kita punya struct tapi bisa ditambahkan method dan interface. Tergantung konsep komponen nya apa.
Single Service
Hari ini kita akan coba bahas mengenai bagaimana membuat satu service. Di service oriented architecture seperti yang kita ketahui kita membagi satu aplikasi yang besar menjadi beberapa service yang berhubungan melalui event. Karena jika kita tidak memecah aplikasi tersebut menjadi bagian yang kecil kita bakalan kesulitan mengerti semua komponen. Ini berlaku untuk aplikasi skala besar ya. Yang memiliki kompleksitas tinggi. Melibatkan banyak pihak dan bisnis proses.
Kalau tidak besar atau hanya seukuran aplikasi perpustakaan mah gak perlu repot-repot ya. Buat aja satu service yang monolith untuk melayani semua. Karena membagi system terdistribusi jadi service itu tidak mudah.
Di aplikasi enterprise biasanya kebanyakan orang mulai dari design ERD dulu. Ini yang buat kacau. Karena semua pasti berhubungan antara satu tabel dengan yang lain. Banyak tali nya. Jadi coupling. Dan itu langsung di generate pake ORM jadi kelas-kelas yang saling terhubung kayak jaring laba2.
Tentu saja maintain nya susah banget, karena untuk mengerti satu kelas kita harus tau kelas yang lain dan seterusnya. Jadi sedapat mungkin jangan mulai dari database dulu. Tapi mulai dari use case dan user story. Selalu bergerak dari apa fungsionalitas yang hendak dicapai.
Layered vs Tiered Architecture
Nah sekarang kita berandai andai dulu kalau aplikasi kita single service. Supaya lebih teratur belajarnya. Dalam satu service kita harus membagi bagi lagi supaya lebih teratur dan mudah dimengerti dan juga gampang maintain nya. Pembagian ini disebut dengan layered architecture.
Ingat layer bukan tier. Karena kalau kita ngomong tentang 3 tier architecture kita langsung melakukan deploys satu bisnis logic, satu persistence dan satu user interface ke dalam box atau server yang terpisah. Padahal architecture itu ada dua sudut pandang. Dari sisi logical dan juga fisikal.
Logical tidak berbicara mengenai deployment tetapi lebih ke pemotongan dan pembagian sistem menjadi service, service menjadi component yang lebih kecil atau kelas. Tidak ada yang menyebutkan bahwa satu service harus di deploy di mesin yang berbeda. Ini yang menjadi salah satu salah implementasi dalam microservice. Dimana logical disamakan dengan fisikal. Satu service langsung satu deployment. Yang terjadi akhirnya distributed monolith. Nanti kita bahas lagi.
Balik lagi ke single service. Satu service dipecah menjadi 3 bagian besar. Kalau TCP/IP kan ada layer juga tapi dia ada 7 ( ingat OSI layer ). Konsepnya adalah layer yang atas dapat melakukan akses terhadap layer yang di bawahnya. Satu arah. Lihat contoh berikut.
Tidak ada juga yang buat patokan harus 3 atau 4 atau 5 ini tergantung kompleksitas dari service tersebut. Perhatikan bahwa database ada di layer yang paling bawah. Dan selalu buat service tersebut pembuatannya dimulai dari presentation atau service layer / API. Jadi User story dulu dibenerin baru kita mulai dengan Test Driven dari level service/API. Jadi programmer backend tidak buat sesuatu yang tidak perlu. Dan integrasi Front End dan Backend bisa dilakukan di awal. Ingat konsep continuous integration. Integrasi dilakukan sesering mungkin.
Untuk aplikasi yang lebih kompleks layer tersebut bisa dipecah lagi.
Ada yang mau pake ORM untuk akses ke database. Ada yang pakai domain object dan yang lain. Domain Object juga diharapkan persistance ignorance. Jadi tidak terikat ke infrastructure ORM atau data layer nya.
Referensi
Jadi satu service itu akan dikerjakan oleh satu team yang fullstack. Tidak perlu punya fullstack developer. Tapi dalam satu team harus terdiri dari developer yang lengkap skill nya. Ada yang FE, BE or UI.
Work as a team guys !
Nah kalau mau lihat apa prinsip2 yang harus dipenuhi di layered architecture bisa lihat ini.
Dan jangan hanya ngoding aja, tapi ingat juga buat dokumentasi. Karena belum tentu yang maintain kita terus kan ya?
Framework
Konsep ini dipakai di banyak framework yang cukup besar. Salah satunya spring framework yang ada di java.
Ada juga di nodejs. NestJS ini juga menggunakan konsep Layered Architecture.
Kayaknya model nya si nest ini nyontek angular deh. Yang familiar dengan object oriented dan layered architecture di enterprise pasti akrab dengan angular architecture. Pemisahaan komponen nya jelas.
Makanya gw suka angular karena emang rapi dari sisi architectureny. Tapi mungkin kalau di user interface rada tinggi learning curve nya buat javascript engineer ya. Ya.. mgkin juga overkill kalau di UI dipaksain seperti itu.
Dependency Injection
Jadi kita sudah sepakat ya kalau satu layer dan layer yang lain gimana komunikasinya ? Gunanya apa dipisah ? Supaya gampang dimengerti dan juga bisa di test dengan gampang. Konsep programming to interface juga menjadi penting. Karena tiap layer ke layer yang lain dependency nya hanya via interface dan bukan concrete class. Jadi bisa replaceable.
Nah gimana cara dia bekerja ? Interface kan hanya contract doang. Makanya ada konsep yang dinamakan Dependency Injection. Jadi kita gak langsung instansiasi object konkrit nya tapi di buat sama container dan di inject ke layer dibawah nya.
Domain Model (Logic + Rules)
Oke sekarang kita bahas yang jadi core logic dari aplikasi kita. Kita biasanya melakukan enkapsulasi terhadap business logic atau rules di domain or business layer. Jadi business layer ini tidak selamanya domain model ya. Ada beberapa pendekatan juga. Jadi kalau emang sederhana gak ush paksain pake domain model.
Banyak orang sekrang suka salah kaprah dengan hype. Sekarang orang dikit2 bilang mau pake Domain driven Design. Padahal yang dipake hanya aggregate root dsb. Sebenarnya kunci dari DDD itu sendiri adalah ubiquitous language. Dari situ kita bisa derive design yang sesuai dengan domain yang kita telaah. Tapi ini ribet dan takes time, namanya juga building model together sama orang bisnis.
Tapi nantilah kita coba bahas tentang itu di artikel berikutnya tentang service oriented architecture ( heaven forbid Microservices ). Sekarang kita fokus ke satu service dulu.
Di business layer atau domain logic ada beberapa pendekatan. Transaction script, Table Module dan Domain Model. Untuk lebih detail baca di buku si martin fowler PoEAA ya. Masing-masing punya kompleksitasnya sendiri. Jadi pick your own poison. Gak pake DDD juga gak salah. Just enough lah. Jangan sampe overkill or over engineering. Not because you can you should kan?
Trus misalnya setelah anda pikir-pikir tetep mau pake domain model ya mari kita masuk ke dunia kompleks tentang DDD. Ya utk masalah yang complex solusinya tentu saja harus rada sedikit mikir dan effort.
Di buku si eric evans di atas ada dijelasin mengenai gimana membuat layer supaya domain model itu bisa testable dan terlindungi dari infrastructure concern. Jadi bisa gampang di modify dan mudah dimengerti karena sesuai dengan bahasa business.
Konsepnya sih sama aja dengan martin fowler, wong mereka temenan kok. Dan ini lebih fokus ke gimana buat domain model nya. Buku biru itu emang tebel dan bahasanya rada susah dimengerti jadi harus dibaca berulang. Jangan sampe 3 bab pertama bosen, trus langsung bilang tau DDD. Padahal intinya itu ada di chapter terakhir mengenai Startegic Design terutama bagian Bounded Context. Itu adalah cikal bakal dari Microservice. Well. SOA sih klo gw pengen konsisten.
Domain Event
Trus gimana domain model bisa komunikasi dengan layer yang di atasnya? Kan kita pake layered architecture. Gak boleh dong ? Jadi jangan terlalu terpaku sama pattern juga. Gak ada yang gak boleh, semua boleh tapi ada compromise. Di awal awal boleh lah latihan tapi pas seiring dengan bertambah nya pengalaman harus lebih wise dan gak boleh kaku. Stress ntar. Relax aja. Yang penting jalan softwarenya, ya gak ? kwkw
Kembali ke pertanyaan tadi, kalau dari domain ada state changes dan kita mw tau gimana dong ? Kan gak bisa domain panggil ke service layer ?
Kalau itu bisa diatasin dengan model event atau domain event. Kita bisa register callback terhadap domain yang kita mau monitor. Ini mirip banget dengan observer pattern atau kalau di c# ada yang namanya delegate or event. Konsepnya sama. Loose coupling. Kita bisa subscribe dan unsubscribe sama perubahaan state satu object. Namanya juga object ya berarti ada state yang di maintain. Ingat definisi class dan object ya.
CQRS and Event Sourcing
Dari domain event ini muncul pattern lain seperti event sourcing dan CQRS. Tapi jangan terpukau sama kilau nya architecture itu. Itu bakalan buat jadi ribet. Gunakan secara bijak. Jangan hajar bleh semua mw di buatin CQRS or Event Sourcing. Gak ada salah nya mulai dari monolith dulu, trus klo bisnis dah cuan ya baru di refactor. Kalau kita ketemu masalah scaling malah bagus kan? Good for business. Tinggal hire orang aja ngerjain ulang. ya gak ? bodo amat. Be wise !
Aku ada kasih reference berikut, tapi mending gak dibaca deh di awal ini. Fokus buatin layered architecture yang benar dan fokus get jobs done. No need to overcomplicate the simple things. Sama aja kok nanti juga di rewrite. Haha
Contoh Domain Event
Kembali ke laptop. Where are we ? Right. Domain Event.
Cara implementasinya ada dibuat sama Udi Dahan di C# tapi. Tapi konsepnya kurang lebih samalah, cuman C# lebih canggih aja. Hehe. Maklumlah bahasa pemrograman modern. Haha
Intinya balik lagi ke observer pattern sih. Ini banyak guna nya loh. Kita bisa buat domain model yang lebih testable dan sedikit setter dan getter.
Interesting stuff. Tapi balik lagi. Sesuaikan dengan kebutuhan. Kalau active record or table module or transaction script cukup ya hajar aja pake itu. Make it work, make it beauty, make it fast.
Outside In TDD
Jadi TDD juga harusnya outside in. Dari service layer masuk ke dalam dan sampe ke domain modelnya. Jadi gak ada yang dibuat sia-sia hanya untuk memuaskan bos yang suka XP or TDD doang. Be wise aja. Tapi kalau mau latihan dan nambahin CV boleh lah bilang klo lo itu Test Infected atau di dada lo ada tatto TDD or DDD or BDD or DBD #eh
Kalau gw biasanya kalau buat domain model yang rumit ya biasanya pake test driven design. Ingat lagi2. Gak semua harus lo TDD-in. Gak guna. Capek tau. Maintain test yang banyak dan se abrek2 itu juga ribet tau. Apalagi kalau interfacenya berubah. Santai aja. Kalo emang lo rasa gak kepikiran gimana cara buat domain modelnya. Ya start with Test first.
Ada juga test while code or test after juga gak masalah. Tergantung kebutuhan. Ya kalau misalnya buat quicksort juga gak perlu juga pake TDD kan ? dah ada pseudocode nya ya hajar aja. Test after juga gak masalah. Kelamaan pake TDD. Terutama kalau gak tau end goal nya or HOW nya sampe ke end itu gimana. Bisa muter2 dibuat TDD.
Emang kalau lo buat DTO or data transfer object perlu di test gak ? Wong isinya setter getter doang.
Ini ada cara untuk buat service yang bener pake TDD dari layer yang paling luar yaitu service layer ( API ) dan sampe ke domain model. Ini bisa ditonton ya.
Oke, sampai sini aja mungkin ya. Untuk cara implementasinya liat di nestjs or angular itu dah lengkap banget sih dan juga self explanatory juga.
Tetap semangat and tetap berkarya.
Cheers