Saya memutuskan apakah saya harus menggunakan Rich Domain Model daripada Anemic Domain Model, dan mencari contoh yang baik dari keduanya.
Saya telah membangun aplikasi web menggunakan Model Domain Anemik, didukung oleh Layanan -> Repositori -> Sistem lapisan penyimpanan , menggunakan FluentValidation untuk validasi BL, dan meletakkan semua BL saya di lapisan Layanan.
Saya telah membaca buku DDD Eric Evan, dan dia (bersama dengan Fowler dan lainnya) tampaknya berpikir Anemic Domain Model adalah anti-pola.
Jadi saya hanya ingin mendapatkan sedikit wawasan tentang masalah ini.
Juga, saya benar-benar mencari beberapa contoh (dasar) yang baik dari Model Domain Kaya, dan keuntungan dari Model Domain Anemik yang diberikannya.
Jawaban:
Perbedaannya adalah model anemia memisahkan logika dari data. Logikanya sering ditempatkan di kelas yang bernama
**Service
,**Util
,**Manager
,**Helper
dan sebagainya. Kelas-kelas ini mengimplementasikan logika interpretasi data dan oleh karena itu mengambil model data sebagai argumen. Misalnyasedangkan pendekatan domain kaya membalik ini dengan menempatkan logika interpretasi data ke dalam model domain kaya. Dengan demikian ia menempatkan logika dan data bersama-sama dan model domain kaya akan terlihat seperti ini:
Ini berdampak besar pada konsistensi objek. Karena logika interpretasi data membungkus data (data hanya dapat diakses melalui metode objek) metode dapat bereaksi terhadap perubahan status data lain -> Inilah yang kita sebut perilaku.
Dalam model anemia model data tidak dapat menjamin bahwa mereka dalam keadaan hukum sementara dalam model domain kaya mereka bisa. Model domain kaya menerapkan prinsip-prinsip OO seperti enkapsulasi, penyembunyian informasi dan menyatukan data dan logika dan oleh karena itu model anemia adalah pola anti dari perspektif OO.
Untuk wawasan yang lebih dalam, lihat blog saya https://www.link-intersystems.com/blog/2011/10/01/anemic-vs-rich-domain-models/
sumber
Bozhidar Bozhanov tampaknya mendukung model anemia di postingan blog ini .
Berikut ringkasan yang dia sajikan:
objek domain tidak boleh dikelola pegas (IoC), objek domain tersebut tidak boleh memiliki DAO atau apa pun yang terkait dengan infrastruktur yang diinjeksikan di dalamnya
objek domain memiliki objek domain tempat mereka bergantung pada set oleh hibernate (atau mekanisme persistensi)
objek domain melakukan logika bisnis, seperti ide inti dari DDD, tetapi ini tidak termasuk kueri database atau operasi CRUD - hanya pada keadaan internal objek
DTO jarang dibutuhkan - objek domain adalah DTO itu sendiri dalam banyak kasus (yang menyimpan beberapa kode boilerplate)
layanan melakukan operasi CRUD, mengirim email, mengoordinasikan objek domain, menghasilkan laporan berdasarkan beberapa objek domain, menjalankan kueri, dll.
lapisan layanan (aplikasi) tidak terlalu tipis, tetapi tidak menyertakan aturan bisnis yang intrinsik ke objek domain
pembuatan kode harus dihindari. Abstraksi, pola desain dan DI harus digunakan untuk mengatasi kebutuhan pembuatan kode, dan pada akhirnya - untuk menyingkirkan duplikasi kode.
MEMPERBARUI
Saya baru-baru ini membaca artikel ini di mana penulis menganjurkan mengikuti semacam pendekatan hybrid - objek domain dapat menjawab berbagai pertanyaan hanya berdasarkan statusnya (yang dalam kasus model anemia total mungkin akan dilakukan di lapisan layanan)
sumber
Sudut pandang saya adalah ini:
Model domain anemia = tabel database yang dipetakan ke objek (hanya nilai bidang, tidak ada perilaku nyata)
Model domain kaya = kumpulan objek yang mengekspos perilaku
Jika ingin membuat aplikasi CRUD sederhana, mungkin model anemia dengan framework MVC klasik sudah cukup. Tetapi jika Anda ingin menerapkan beberapa jenis logika, model anemia berarti Anda tidak akan melakukan pemrograman berorientasi objek.
* Perhatikan bahwa perilaku objek tidak ada hubungannya dengan ketekunan. Lapisan yang berbeda (Pemetaan Data, Repositori, dll.) Bertanggung jawab untuk mempertahankan objek domain.
sumber
x
,y
,sum
dandifference
. Itu empat hal. Atau Anda bisa membantah itu penambahan dan pengurangan (dua hal). Atau Anda bisa membantah bahwa itu matematika (satu hal). Ada banyak posting blog di luar sana tentang bagaimana Anda menemukan keseimbangan dalam menerapkan SRP. Ini salah satunya: hackernoon.com/…Gambar 1 menunjukkan Model Domain Anemik, yang pada dasarnya adalah skema dengan getter dan setter.
Dalam model yang lebih kaya ini, daripada hanya menampilkan properti untuk dibaca dan ditulis, permukaan publik Pelanggan terdiri dari metode eksplisit.
sumber
Address
, tetapiExtendedAddress
, diwarisi dariAddress
, dengan beberapa properti tambahan? 2) Atau ubahCustomerCreditCard
parameter konstruktor untuk diambilBankID
alih-alihBankName
?Salah satu keuntungan kelas domain kaya adalah Anda dapat memanggil perilaku mereka (metode) setiap kali Anda memiliki referensi ke objek di lapisan mana pun. Selain itu, Anda cenderung menulis metode kecil dan terdistribusi yang berkolaborasi bersama. Dalam kelas domain anemia, Anda cenderung menulis metode prosedural gemuk (di lapisan layanan) yang biasanya didorong oleh kasus penggunaan. Mereka biasanya kurang dapat dipelihara dibandingkan dengan kelas domain kaya.
Contoh kelas domain dengan perilaku:
Metode
needToDeliver()
akan mengembalikan daftar item yang perlu dikirimkan termasuk bonus. Itu bisa dipanggil di dalam kelas, dari kelas lain yang terkait, atau dari lapisan lain. Misalnya, jika Anda lolosOrder
ke tampilan, maka Anda dapat menggunakanneedToDeliver()
pilihanOrder
untuk menampilkan daftar item yang akan dikonfirmasi oleh pengguna sebelum mereka mengklik tombol simpan untuk mempertahankanOrder
.Menanggapi Komentar
Beginilah cara saya menggunakan kelas domain dari pengontrol:
Pembuatan
Order
danLineItem
dalam satu transaksi. Jika salah satu dariLineItem
tidak dapat dibuat, tidakOrder
akan dibuat.Saya cenderung memiliki metode yang mewakili satu transaksi, seperti:
Semua yang ada di dalamnya
deliver()
akan dieksekusi sebagai satu transaksi tunggal. Jika saya perlu menjalankan banyak metode yang tidak terkait dalam satu transaksi, saya akan membuat kelas layanan.Untuk menghindari pengecualian pemuatan lambat, saya menggunakan JPA 2.1 bernama grafik entitas. Misalnya, dalam pengontrol untuk layar pengiriman, saya dapat membuat metode untuk memuat
delivery
atribut dan mengabaikanbonus
, sepertirepository.findOrderByNumberFetchDelivery()
. Di layar bonus, saya memanggil metode lain yang memuatbonus
atribut dan mengabaikandelivery
, sepertirepository.findOrderByNumberFetchBonus()
. Ini membutuhkan disiplin karena saya masih tidak bisa menelepondeliver()
di dalam layar bonus.sumber
Saat saya biasa menulis aplikasi desktop monolitik, saya membuat model domain yang kaya, dulu senang membuatnya.
Sekarang saya menulis layanan mikro HTTP kecil, kode sesedikit mungkin, termasuk DTO anemia.
Saya pikir DDD dan argumen anemia ini berasal dari era aplikasi desktop atau server monolitik. Saya ingat era itu dan saya setuju bahwa model anemia itu aneh. Saya membuat aplikasi trading FX monolitik yang besar dan tidak ada modelnya, sungguh, itu mengerikan.
Dengan layanan mikro, layanan kecil dengan perilakunya yang kaya, bisa dibilang merupakan model yang dapat disusun dan digabungkan dalam suatu domain. Jadi implementasi layanan mikro itu sendiri mungkin tidak memerlukan DDD lebih lanjut. Aplikasi microservice mungkin domainnya.
Layanan mikro pesanan mungkin memiliki fungsi yang sangat sedikit, diekspresikan sebagai sumber daya yang tenang atau melalui SOAP atau apa pun. Kode layanan mikro pesanan mungkin sangat sederhana.
Layanan tunggal (mikro) yang lebih monolitik yang lebih besar, terutama yang mempertahankan modelnya dalam RAM, dapat memanfaatkan DDD.
sumber
Saya pikir akar masalahnya ada pada dikotomi yang salah. Bagaimana mungkin mengekstrak 2 model ini: kaya dan "anemia" dan membedakannya satu sama lain? Saya pikir itu hanya mungkin jika Anda memiliki ide yang salah tentang apa itu kelas . Saya tidak yakin, tapi saya rasa saya menemukannya di salah satu video Bozhidar Bozhanov di Youtube. Kelas bukanlah metode data + atas data ini. Pemahaman yang sama sekali tidak valid yang mengarah pada pembagian kelas menjadi dua kategori: hanya data, jadi model anemia dan metode + data - jadi model kaya (untuk lebih tepatnya ada kategori ke-3: hanya metode genap).
Yang benar adalah bahwa kelas adalah konsep dalam beberapa model ontologis, kata, definisi, istilah, ide, itu DENOTAT . Dan pemahaman ini menghilangkan dikotomi palsu: Anda tidak dapat memiliki HANYA model anemia atau HANYA model kaya, karena itu berarti model Anda tidak memadai, tidak relevan dengan kenyataan: beberapa konsep hanya memiliki data, beberapa di antaranya hanya memiliki metode, beberapa dari mereka dicampur. Karena kita mencoba mendeskripsikan, dalam hal ini, beberapa kategori, himpunan objek, relasi, konsep dengan kelas, dan seperti yang kita ketahui, beberapa konsep hanya proses (metode), beberapa di antaranya adalah himpunan atribut saja (data), beberapa di antaranya adalah mereka adalah hubungan dengan atribut (campuran).
Saya pikir aplikasi yang memadai harus mencakup semua jenis kelas dan untuk menghindari pembatasan diri secara fanatik hanya pada satu model. Tidak masalah, bagaimana logika merepresentasikan: dengan kode atau dengan objek data yang dapat diinterpretasikan (seperti Free Monads ), bagaimanapun: kita harus memiliki kelas (konsep, denotat) yang mewakili proses, logika, relasi, atribut, fitur, data, dll. Dan bukan untuk mencoba menghindari beberapa dari mereka atau untuk mereduksi semuanya menjadi satu jenis saja.
Jadi, kita dapat mengekstrak logika ke kelas lain dan meninggalkan data dalam yang asli, tetapi itu tidak masuk akal karena beberapa konsep dapat menyertakan atribut dan relasi / proses / metode dan pemisahannya akan menduplikasi konsep di bawah 2 nama yang dapat direduksi menjadi pola: "OBJECT-Attributes" dan "OBJECT-Logic". Tidak apa-apa dalam bahasa prosedural dan fungsional karena keterbatasannya tetapi itu menahan diri secara berlebihan untuk bahasa yang memungkinkan Anda mendeskripsikan semua jenis konsep.
sumber
Model domain anemia penting untuk ORM dan transfer mudah melalui jaringan (darah kehidupan dari semua aplikasi komersial) tetapi OO sangat penting untuk enkapsulasi dan menyederhanakan bagian 'transaksional / penanganan' dari kode Anda.
Oleh karena itu yang penting adalah dapat mengidentifikasi dan mengubah dari satu dunia ke dunia lainnya.
Beri nama model Anemic sesuatu seperti AnemicUser, atau UserDAO dll sehingga pengembang tahu ada kelas yang lebih baik untuk digunakan, kemudian memiliki konstruktor yang sesuai untuk kelas Anemic none
dan metode adaptor untuk membuat kelas anemia untuk pengangkutan / persistensi
Bertujuan untuk menggunakan tidak ada Pengguna Anemik di mana-mana di luar transportasi / persistensi
sumber
Berikut adalah contoh yang mungkin membantu:
Anemia
Non-anemia
sumber
Pendekatan klasik untuk DDD tidak menyatakan untuk menghindari Anemic vs Rich Model di semua biaya. Namun, MDA masih dapat menerapkan semua konsep DDD (konteks terbatas, peta konteks, objek nilai, dll.) Tetapi menggunakan model Anemic vs Rich dalam semua kasus. Ada banyak kasus di mana menggunakan Layanan Domain untuk mengatur Kasus Penggunaan Domain yang kompleks di sekumpulan agregat domain sebagai pendekatan yang jauh lebih baik daripada sekadar agregat yang dipanggil dari lapisan aplikasi. Satu-satunya perbedaan dari pendekatan DDD klasik adalah di mana letak semua validasi dan aturan bisnis? Ada konstruksi baru yang dikenal sebagai validator model. Validator memastikan integritas model input lengkap sebelum kasus penggunaan atau alur kerja domain berlangsung. Akar agregat dan entitas anak mengalami anemia tetapi masing-masing dapat memiliki validator modelnya sendiri yang dipanggil sesuai kebutuhan, dengan validator rootnya. Validator masih mengikuti SRP, mudah dirawat dan dapat diuji unit.
Alasan pergeseran ini adalah kami sekarang bergerak lebih ke API first vs pendekatan UX first ke Microservices. REST telah memainkan peran yang sangat penting dalam hal ini. Pendekatan API tradisional (karena SOAP) awalnya terpaku pada API berbasis perintah vs. verba HTTP (POST, PUT, PATCH, GET dan DELETE). API berbasis perintah cocok dengan pendekatan berorientasi objek Model Kaya dan masih sangat valid. Namun, API berbasis CRUD sederhana, meskipun dapat ditampung dalam Model Kaya, jauh lebih cocok dengan model anemia sederhana, validator, dan Layanan Domain untuk mengatur sisanya.
Saya suka DDD dalam semua yang ditawarkannya, tetapi ada saatnya Anda perlu meregangkannya sedikit agar sesuai dengan pendekatan arsitektur yang terus berubah dan lebih baik.
sumber