Di mana kita menarik garis antara delegasi dan enkapsulasi logika bisnis? Tampak bagi saya bahwa semakin kita mendelegasikan, kita menjadi semakin anemia . Namun, delegasi juga mempromosikan penggunaan kembali dan kepala sekolah KERING. Jadi apa yang pantas untuk didelegasikan dan apa yang harus tetap dalam model domain kami?
Ambil keprihatinan berikut sebagai contoh:
Otorisasi . Haruskah objek domain bertanggung jawab untuk mempertahankan aturan kontrol aksesnya (seperti properti CanEdit) atau haruskah itu didelegasikan ke komponen / layanan lain yang semata-mata bertanggung jawab untuk mengelola akses, mis. IAuthorizationService.CanEdit (objek)? Atau haruskah itu kombinasi keduanya? Mungkin objek domain memiliki properti CanEdit yang mendelegasikan ke IAuthorizationService internal untuk melakukan pekerjaan yang sebenarnya?
Validasi . Diskusi yang sama seperti di atas berkaitan dengan validasi. Siapa yang memelihara aturan dan siapa yang bertanggung jawab untuk mengevaluasinya? Di satu sisi, keadaan objek harus milik objek itu dan validitas adalah keadaan tetapi kami tidak ingin menulis ulang kode yang digunakan untuk mengevaluasi aturan untuk setiap objek domain. Kita bisa menggunakan warisan dalam kasus ini ...
Penciptaan Obyek . Kelas pabrik versus metode pabrik versus 'memulai' sebuah instance. Jika kita menggunakan kelas pabrik yang terpisah, kita dapat mengisolasi dan merangkum logika penciptaan tetapi dengan mengorbankan membuka objek objek kita ke pabrik. Ini dapat dikelola jika lapisan domain kami berada dalam rakitan terpisah dengan memaparkan konstruktor internal yang digunakan oleh pabrik tetapi ini menjadi masalah jika ada beberapa pola pembuatan. Dan, jika semua pabrik lakukan adalah memanggil konstruktor yang tepat, apa gunanya memiliki pabrik?
Metode pabrik di kelas menghilangkan masalah dengan membuka keadaan internal objek tetapi karena mereka statis, kami tidak dapat memecah ketergantungan melalui injeksi antarmuka pabrik seperti yang kami bisa dengan kelas pabrik terpisah.
Ketekunan . Orang dapat berargumen bahwa jika objek domain kita akan mengekspos CanEdit sambil mendelegasikan tanggung jawab untuk melakukan pemeriksaan otorisasi kepada pihak lain (IAuthorizationService) mengapa tidak memiliki metode Simpan pada objek domain kita yang melakukan hal yang sama? Ini akan memungkinkan kita untuk mengevaluasi keadaan internal objek untuk menentukan apakah operasi dapat dilakukan tanpa melanggar enkapsulasi. Tentu saja mengharuskan kami menyuntikkan instance repositori ke objek domain kami, yang baunya sedikit bagi saya, jadi apakah kami akan memunculkan event domain dan mengizinkan pawang untuk melakukan operasi persisten?
Lihat ke mana saya akan pergi dengan ini?
Rockford Lhotka memiliki diskusi besar tentang alasannya untuk pergi rute Class-in-Charge untuk kerangka CSLA-nya dan saya memiliki sedikit sejarah dengan kerangka kerja itu dan dapat melihat idenya tentang objek bisnis yang sejajar dengan objek domain dalam banyak cara. Tetapi mencoba menjadi lebih taat pada cita-cita DDD yang baik, saya bertanya-tanya kapan kolaborasi menjadi terlalu banyak.
Jika saya berakhir dengan IAuthorizationService, IValidator, IFactory dan IRepository untuk root agregat saya, apa yang tersisa? Apakah memiliki metode Publikasikan yang mengubah keadaan objek dari Draf ke Diterbitkan cukup untuk mempertimbangkan kelas sebagai objek domain non-anemia?
Pikiran Anda?
sumber
Jawaban:
Sebagian besar kebingungan tampaknya berada di sekitar fungsi yang seharusnya tidak ada dalam model domain sama sekali:
Kegigihan tidak boleh ada dalam model domain. Tidak akan pernah. Itulah alasan Anda mengandalkan tipe abstrak seperti
IRepository
jika bagian dari model perlu melakukan sesuatu seperti mengambil bagian yang berbeda dari model, dan menggunakan injeksi ketergantungan atau teknik serupa untuk memasang implementasi. Jadi serang itu dari rekaman.Otorisasi biasanya bukan bagian dari model domain Anda, kecuali itu sebenarnya bagian dari domain, misalnya jika Anda sedang menulis perangkat lunak keamanan. Mekanisme siapa yang diizinkan untuk melakukan apa yang ada dalam suatu aplikasi biasanya ditangani di "tepi" tingkat bisnis / domain, bagian publik tempat UI dan bagian Integrasi diizinkan untuk berbicara dengan - Pengendali dalam MVC, Layanan atau sistem pesan itu sendiri dalam SOA ... Anda mendapatkan gambar.
Pabrik (dan saya berasumsi maksud Anda pabrik abstrak di sini) tidak terlalu buruk untuk dimiliki dalam model domain tetapi hampir selalu tidak perlu. Biasanya Anda hanya memiliki pabrik ketika mekanisme dalam penciptaan objek mungkin berubah. Tetapi Anda hanya memiliki satu implementasi model domain, yang berarti bahwa hanya akan ada satu jenis pabrik yang selalu memanggil konstruktor yang sama dan kode inisialisasi lainnya.
Anda dapat memiliki pabrik "kenyamanan" jika Anda mau - kelas yang merangkum kombinasi umum parameter konstruktor dan sebagainya - tetapi jujur, secara umum, jika Anda memiliki banyak pabrik yang duduk dalam model domain Anda maka Anda hanya membuang-buang waktu kode.
Jadi begitu Anda mencabut semua itu, itu hanya meninggalkan validasi. Itu satu-satunya yang agak rumit.
Validasi adalah bagian dari model domain Anda tetapi juga merupakan bagian dari setiap komponen aplikasi lainnya. UI dan basis data Anda akan memiliki aturan validasi yang serupa namun berbeda, berdasarkan model konseptual yang serupa namun berbeda. Itu tidak benar-benar ditentukan apakah objek perlu memiliki
Validate
metode atau tidak, tetapi bahkan jika mereka melakukannya, mereka biasanya akan mendelegasikannya ke kelas validator (bukan antarmuka - validasi tidak abstrak dalam model domain, itu mendasar).Ingatlah bahwa validator secara teknis masih menjadi bagian dari model; itu tidak perlu dilampirkan ke root agregat karena tidak mengandung data atau keadaan apa pun. Model domain adalah hal-hal konseptual, biasanya diterjemahkan secara fisik ke sebuah majelis atau kumpulan majelis. Jangan menekankan masalah "anemia" jika kode delegasi Anda berada sangat dekat dengan model objek; masih diperhitungkan.
Apa ini benar-benar turun adalah bahwa jika Anda akan melakukan DDD, Anda harus memahami apa domain adalah . Jika Anda masih berbicara tentang hal-hal seperti kegigihan dan otorisasi maka Anda berada di jalur yang salah. Domain mewakili keadaan sistem yang sedang berjalan - objek dan atribut fisik dan konseptual. Apa pun yang tidak secara langsung relevan dengan objek dan hubungan itu sendiri tidak termasuk dalam model domain, titik.
Sebagai patokan, ketika mempertimbangkan apakah sesuatu termasuk dalam model domain, tanyakan pada diri sendiri pertanyaan berikut:
"Bisakah fungsi ini berubah karena alasan teknis semata?" Dengan kata lain, bukan karena perubahan yang terlihat pada bisnis atau domain dunia nyata?
Jika jawabannya "ya", maka itu tidak termasuk dalam model domain. Itu bukan bagian dari domain.
Kemungkinan besar, suatu hari nanti, Anda akan mengubah ketekunan dan infrastruktur otorisasi Anda. Oleh karena itu, mereka bukan bagian dari domain, mereka adalah bagian dari aplikasi. Ini juga berlaku untuk algoritma, seperti pengurutan dan pencarian; Anda tidak boleh pergi dan mendorong implementasi kode pencarian biner ke dalam model domain Anda, karena domain Anda hanya mementingkan konsep abstrak pencarian, bukan cara kerjanya.
Jika, setelah Anda menghapus semua hal yang tidak penting, Anda menemukan bahwa model domain benar-benar anemia , maka itu akan berfungsi sebagai indikasi yang cukup baik bahwa DDD hanyalah paradigma yang salah untuk proyek Anda.
Beberapa domain benar - benar anemia. Aplikasi bookmark sosial tidak memiliki banyak "domain" untuk dibicarakan; semua objek Anda pada dasarnya hanya data tanpa fungsi. Di sisi lain, sistem Penjualan dan CRM memiliki domain yang cukup berat; ketika Anda memuat
Rate
entitas maka ada harapan yang masuk akal bahwa Anda benar - benar dapat melakukan hal - hal dengan tingkat itu, seperti menerapkannya pada kuantitas pesanan dan minta tahu volume diskon dan kode promo dan semua hal menyenangkan itu.Benda domain yang hanya menyimpan data biasanya tidak berarti bahwa Anda memiliki model domain anemia, tapi itu tidak selalu berarti bahwa Anda telah membuat desain yang buruk - itu mungkin hanya berarti bahwa domain itu sendiri adalah anemia dan bahwa Anda harus menggunakan metodologi yang berbeda.
sumber
Tidak. Otorisasi adalah masalah tersendiri. Perintah yang tidak valid karena kurangnya izin harus ditolak sebelum domain, sedini mungkin - yang berarti seringkali kita bahkan ingin memeriksa otorisasi perintah potensial untuk membangun UI (agar tidak bahkan menunjukkan kepada pengguna opsi pengeditan).
Berbagi strategi otorisasi lintas lapisan (di UI dan lebih jauh dalam layanan atau penangan perintah) lebih mudah ketika otorisasi dipisah-pisahkan terpisah dari model domain.
Satu bagian rumit yang dapat ditemui adalah otorisasi kontekstual, di mana perintah mungkin atau mungkin tidak diizinkan tidak hanya berdasarkan peran pengguna tetapi juga data / aturan bisnis.
Saya juga akan mengatakan tidak, tidak dalam domain (kebanyakan). Validasi terjadi dalam konteks yang berbeda, dan aturan validasi sering berbeda di antara konteks. Jarang ada rasa sederhana, absolut valid atau tidak valid ketika mempertimbangkan data yang dienkapsulasi oleh agregat.
Juga, seperti otorisasi, kami menggunakan logika validasi lintas lapisan - di UI, di layanan atau penangan perintah, dll. Sekali lagi, lebih mudah untuk menggunakan KERING dengan validasi jika itu adalah komponen yang terpisah. Dari titik praktis, validasi (terutama ketika menggunakan kerangka kerja) membutuhkan pengungkapan data yang seharusnya dienkapsulasi dan seringkali memerlukan atribut khusus untuk dilampirkan ke bidang dan properti. Saya lebih suka ini berada di kelas lain daripada model domain saya.
Saya lebih suka menduplikasi beberapa properti dalam beberapa kelas yang serupa daripada mencoba memaksa persyaratan untuk kerangka kerja validasi ke entitas saya. Yang pasti akhirnya membuat kekacauan kelas entitas.
Saya menggunakan satu lapisan tipuan. Dalam proyek saya yang lebih baru, ini adalah perintah + penangan untuk membuat sesuatu, yaitu
CreateNewAccountCommand
. Alternatif bisa selalu menggunakan pabrik (meskipun itu bisa canggung jika sisa operasi entitas terkena oleh kelas layanan yang terpisah dari kelas pabrik).Secara umum, saya mencoba untuk lebih fleksibel dengan pilihan desain untuk pembuatan objek.
new
mudah dan akrab tetapi tidak selalu cukup. Saya pikir menggunakan penilaian di sini dan memungkinkan berbagai bagian sistem untuk menggunakan strategi yang berbeda sesuai kebutuhan adalah penting.Ini jarang merupakan ide yang bagus; Saya pikir ada banyak pengalaman bersama untuk mendukung itu.
Mungkin model domain bukan pilihan yang tepat untuk bagian aplikasi Anda ini.
sumber
OK, ini dia. Saya akan mengosongkan ini dengan mengatakan bahwa:
Optimalisasi prematur (dan itu termasuk desain) seringkali dapat menyebabkan masalah.
IANMF (saya bukan Martin Fowler);)
Sebuah rahasia kecil yang kotor adalah bahwa pada proyek-proyek berukuran kecil (bahkan yang berukuran sedang), konsistensi pendekatan Anda yang penting.
Otorisasi
Bagi saya Otentikasi dan Otorisasi selalu menjadi perhatian lintas sektoral. Di dunia Jawa kecil saya yang bahagia, yang akan didelegasikan ke keamanan Spring atau kerangka kerja Apache Shiro.
Validasi Bagi saya validasi adalah bagian dari objek, seperti yang saya lihat sebagai definisi objek.
misalnya objek Mobil memiliki 4 roda (OK ada beberapa pengecualian aneh, tapi mari kita abaikan Mobil roda 3 yang aneh untuk saat ini). Mobil sama sekali tidak valid kecuali memiliki 4 (di dunia saya), sehingga validasi adalah bagian dari definisi Mobil. Itu tidak berarti Anda tidak dapat memiliki kelas validasi pembantu.
Di dunia Java saya yang bahagia, saya menggunakan kerangka validasi Bean dan menggunakan anotasi sederhana pada sebagian besar bidang Bean saya. Maka mudah untuk memvalidasi objek Anda, apa pun lapisannya.
Penciptaan Obyek
Saya melihat kelas-kelas Pabrik dengan hati-hati. Terlalu sering saya melihat
xyxFactoryFactory
kelas;)Saya cenderung hanya membuat
new
objek sesuai kebutuhan, sampai saya mengalami kasus di mana Injeksi Ketergantungan diperlukan (dan karena saya mencoba mengikuti pendekatan TDD, ini muncul lebih sering daripada tidak).Di dunia Jawa bahagia saya yang semakin Guice, tetapi Musim Semi masih Raja di sini.
Kegigihan
Jadi ini debat yang berlangsung dalam lingkaran dan bundaran dan saya selalu dalam dua pikiran tentang hal itu.
Beberapa mengatakan bahwa jika Anda melihat objek dengan cara yang 'murni', kegigihan bukanlah properti inti, itu hanya masalah luar.
Orang lain mengambil pandangan bahwa objek domain Anda secara implisit mengimplementasikan antarmuka yang 'dapat bertahan' (ya saya tahu saya merentangkan sini). Oleh karena itu, boleh saja menggunakan berbagai metode
save
,delete
dll. Ini dipandang sebagai pendekatan pragmatis dan banyak teknologi ORM (JPA di dunia Java saya yang bahagia) menangani objek dengan cara ini.Dari masalah keamanan lintas sektor saya memastikan bahwa izin edit / hapus / tambahkan / apa pun diatur dengan benar pada layanan yang memanggil metode save / update / delete pada objek. Jika saya benar-benar paranoid saya bahkan mungkin mengatur izin pada objek domain itu sendiri.
HTH!
sumber
Jimmy Nilsson menyentuh topik ini dalam bukunya tentang DDD. Dia mulai dengan model anemia, pergi ke model non-anemia pada proyek kemudian dan akhirnya memilih model anemia. Alasannya adalah bahwa model anemia dapat digunakan kembali dalam berbagai layanan dengan logika bisnis yang berbeda.
Imbalannya adalah kurangnya kemampuan menemukan. Metode yang dapat Anda gunakan untuk beroperasi pada model anemia Anda tersebar di seluruh rangkaian layanan yang terletak di tempat lain.
sumber
Pertanyaan ini sudah lama ditanyakan, tetapi ditandai dengan Desain Domain Driven. Saya pikir pertanyaan itu sendiri mengandung kesalahpahaman mendasar dari seluruh praktik dan jawaban, termasuk jawaban yang diterima, mengabadikan kesalahpahaman mendasar.
Tidak ada "model domain" dalam arsitektur DDD.
Mari kita ambil Otorisasi sebagai contoh. Biarkan saya meminta Anda memikirkan pertanyaan: bayangkan dua pengguna berbeda mengautentikasi dengan sistem Anda. Satu pengguna memiliki izin untuk mengubah Entitas tertentu, tetapi yang lain tidak. Kenapa tidak?
Saya benci contoh-contoh sederhana dan dibuat-buat karena sering membingungkan lebih banyak daripada yang dicerahkan. Tapi mari kita berpura-pura memiliki dua domain berbeda. Pertama adalah platform CMS untuk agen pemasaran. Agensi ini memiliki banyak pelanggan yang semuanya memiliki konten online yang perlu dikelola oleh penulis salinan dan seniman grafis. Konten tersebut mencakup posting blog serta halaman arahan untuk pelanggan yang berbeda.
Domain lainnya adalah manajemen inventaris untuk perusahaan sepatu. Sistem ini mengelola inventaris mulai saat tiba dari produsen di Prancis, ke pusat distribusi di benua AS, ke toko ritel di pasar lokal, dan akhirnya ke pelanggan yang membeli sepatu di ritel.
Jika Anda berpikir bahwa aturan Otorisasi sama untuk kedua perusahaan, maka ya itu akan menjadi kandidat yang baik untuk layanan di luar domain. Tetapi saya ragu bahwa aturan Otorisasi sama. Bahkan konsep di balik pengguna akan berbeda. Tentu bahasanya akan berbeda. Agen pemasaran mungkin memiliki peran seperti penulis pos dan pemilik aset, sedangkan perusahaan sepatu mungkin memiliki peran seperti petugas pengiriman atau manajer gudang, atau manajer toko.
Konsep-konsep ini mungkin memiliki semua jenis aturan izin yang terkait dengannya yang perlu dimodelkan dalam domain. Tapi itu tidak berarti mereka semua adalah bagian dari model yang sama bahkan di dalam aplikasi yang sama. Karena ingatlah bahwa ada konteks terikat yang berbeda.
Jadi mungkin seseorang dapat mempertimbangkan model domain non-anemik dalam konteks Otorisasi berbeda dari konteks pengiriman rute sepatu ke toko dengan inventaris rendah atau mengarahkan pengunjung situs ke halaman arahan yang sesuai tergantung pada iklan mana yang mereka klik.
Jika Anda menemukan diri Anda dengan model domain anemia, mungkin Anda hanya perlu menghabiskan lebih banyak waktu pada pemetaan konteks sebelum Anda mulai menulis kode.
sumber