Saya menyelami konsep-konsep Desain Domain-Driven (DDD) dan menemukan beberapa prinsip aneh, terutama mengenai isolasi domain dan model ketekunan. Inilah pemahaman dasar saya:
- Layanan pada lapisan aplikasi (menyediakan serangkaian fitur) meminta objek domain dari repositori yang diperlukan untuk menjalankan fungsinya.
- Implementasi konkret dari repositori ini mengambil data dari penyimpanan yang diimplementasikan untuknya
- Layanan memberi tahu objek domain, yang merangkum logika bisnis, untuk melakukan tugas-tugas tertentu yang mengubah keadaannya.
- Layanan memberi tahu repositori untuk tetap mempertahankan objek domain yang dimodifikasi.
- Repositori perlu memetakan objek domain kembali ke representasi terkait dalam penyimpanan.
Sekarang, dengan asumsi di atas, yang berikut ini tampak canggung:
Iklan 2 .:
Model domain tampaknya memuat seluruh objek domain (termasuk semua bidang dan referensi), bahkan jika mereka tidak diperlukan untuk fungsi yang memintanya. Memuat seluruhnya mungkin bahkan tidak mungkin jika objek domain lain direferensikan, kecuali jika Anda memuat objek domain tersebut juga dan semua objek yang dirujuk secara bergantian, dan seterusnya dan seterusnya. Pemuatan malas muncul di pikiran, yang berarti bahwa Anda mulai menanyakan objek domain Anda yang seharusnya menjadi tanggung jawab repositori.
Mengingat masalah ini, cara "benar" memuat objek domain tampaknya memiliki fungsi pemuatan khusus untuk setiap kasus penggunaan. Fungsi-fungsi khusus ini hanya akan memuat data yang diperlukan oleh use case mereka dirancang untuk. Di sinilah kejanggalan berperan: Pertama, saya harus mempertahankan sejumlah besar fungsi pemuatan untuk setiap implementasi repositori, dan objek domain akan berakhir di keadaan tidak lengkap yang dibawa null
di bidangnya. Yang terakhir seharusnya secara teknis tidak menjadi masalah karena jika suatu nilai tidak dimuat, itu seharusnya tidak diperlukan oleh fungsi yang memintanya. Masih canggung dan potensi bahaya.
Iklan 3 .:
Bagaimana objek domain memverifikasi keunikan kendala pada konstruksi jika tidak memiliki gagasan tentang repositori? Misalnya, jika saya ingin membuat yang baru User
dengan nomor jaminan sosial yang unik (yang diberikan), konflik paling awal akan terjadi setelah meminta repositori untuk menyimpan objek, hanya jika ada batasan keunikan yang ditentukan pada database. Kalau tidak, saya bisa mencari User
dengan jaminan sosial yang diberikan dan melaporkan kesalahan jika ada, sebelum membuat yang baru. Tapi kemudian cek kendala akan tinggal di layanan dan bukan di objek domain tempat mereka berada. Saya baru menyadari bahwa objek domain sangat diperbolehkan menggunakan repositori (disuntikkan) untuk validasi.
Iklan 5 .:
Saya melihat pemetaan objek domain ke backend penyimpanan sebagai proses yang padat karya dibandingkan dengan objek domain yang memodifikasi data yang mendasari secara langsung. Tentu saja, ini merupakan prasyarat penting untuk memisahkan implementasi penyimpanan konkret dari kode domain. Namun, apakah ini memang mahal?
Anda tampaknya memiliki opsi untuk menggunakan alat ORM untuk melakukan pemetaan untuk Anda. Ini sering mengharuskan Anda untuk merancang model domain sesuai dengan batasan ORM, namun, atau bahkan memperkenalkan ketergantungan dari domain ke lapisan infrastruktur (misalnya, dengan menggunakan anotasi ORM dalam objek domain). Saya juga pernah membaca bahwa ORM memperkenalkan overhead komputasi yang cukup besar.
Dalam kasus database NoSQL, yang hampir tidak ada konsep seperti ORM, bagaimana Anda melacak properti yang diubah dalam model domain save()
?
Sunting : Juga, agar repositori dapat mengakses keadaan objek domain (yaitu nilai dari setiap bidang), objek domain perlu mengungkapkan status internalnya yang memecah enkapsulasi.
Secara umum:
- Ke mana logika transaksional pergi? Ini tentu saja merupakan kegigihan yang spesifik. Beberapa infrastruktur penyimpanan mungkin bahkan tidak mendukung transaksi sama sekali (seperti repositori tiruan dalam memori).
- Untuk operasi massal yang memodifikasi banyak objek, apakah saya harus memuat, memodifikasi, dan menyimpan setiap objek secara terpisah untuk dapat melalui logika validasi yang dienkapsulasi objek? Itu bertentangan dengan mengeksekusi permintaan tunggal langsung ke database.
Saya akan sangat menghargai beberapa klarifikasi tentang topik ini. Apakah asumsi saya benar? Jika tidak, apa cara yang benar untuk mengatasi masalah ini?
Jawaban:
Pemahaman dasar Anda benar dan arsitektur yang Anda sketsa bagus dan berfungsi dengan baik.
Membaca yang tersirat sepertinya Anda berasal dari gaya pemrograman catatan aktif yang lebih berbasis database? Untuk mencapai implementasi yang berjalan saya akan mengatakan Anda perlu
1: Objek domain tidak harus menyertakan seluruh grafik objek. Misalnya saya dapat memiliki:
Alamat dan Pelanggan hanya perlu menjadi bagian dari agregat yang sama jika Anda memiliki logika seperti, "nama pelanggan hanya dapat dimulai dengan huruf yang sama dengan nama rumah". Anda benar untuk menghindari pemuatan yang malas dan versi objek Lite.
2: Kendala keunikan umumnya adalah bidang repositori, bukan objek domain. Jangan menyuntikkan repositori ke Objek Domain, itu adalah langkah kembali ke catatan aktif, cukup kesalahan ketika layanan mencoba untuk menyimpan.
Aturan bisnis bukan "Tidak ada dua contoh Pengguna dengan SocialSecurityNumber yang sama dapat ada pada saat yang sama"
Itu karena mereka tidak bisa ada di repositori yang sama.
3: Tidaklah sulit untuk menulis repositori daripada metode pembaruan properti individual. Bahkan, Anda akan menemukan bahwa Anda memiliki kode yang hampir sama. Hanya kelas mana Anda memasukkannya.
ORM hari ini mudah dan tidak memiliki kendala tambahan pada kode Anda. Karena itu, secara pribadi saya lebih suka hanya tangan engkol SQL. Tidak sulit, Anda tidak pernah mengalami masalah dengan fitur ORM dan Anda dapat mengoptimalkan jika diperlukan.
Benar-benar tidak perlu untuk melacak properti mana yang berubah saat Anda menyimpan. Pertahankan Objek Domain Anda kecil dan cukup timpa versi lama.
Pertanyaan Umum
Logika transaksi berlaku di repositori. Tetapi Anda tidak harus memiliki banyak jika ada. Tentu Anda memerlukan beberapa jika Anda memiliki tabel anak di mana Anda meletakkan objek anak-anak dari agregat, tapi itu akan sepenuhnya dienkapsulasi dalam metode repositori SaveMyObject.
Pembaruan massal. Ya, Anda harus mengubah masing-masing objek secara individual lalu tambahkan saja metode SaveMyObjects (Daftar objek) ke repositori Anda, untuk melakukan pembaruan massal.
Anda ingin Objek Domain atau Layanan Domain mengandung logika. Bukan basis data. Itu berarti Anda tidak bisa begitu saja "memperbarui nama set pelanggan = x di mana y", karena untuk semua yang Anda tahu objek Pelanggan, atau CustomerUpdateService melakukan 20 hal aneh ketika Anda mengubah nama.
sumber
AddressId
bukanAddress
) bertentangan dengan prinsip OO?Jawaban singkat: Pemahaman Anda benar dan pertanyaan-pertanyaan yang Anda miliki menunjukkan masalah-masalah valid yang solusinya tidak langsung atau diterima secara universal.
Butir 2 .: (memuat grafik objek lengkap)
Saya bukan yang pertama menunjukkan bahwa ORM tidak selalu merupakan solusi yang baik. Masalah utama adalah bahwa ORM tidak tahu apa-apa tentang kasus penggunaan yang sebenarnya, sehingga mereka tidak tahu harus memuat apa atau bagaimana mengoptimalkan. Ini adalah sebuah masalah.
Seperti yang Anda katakan, solusi yang jelas adalah memiliki metode kegigihan untuk setiap kasus penggunaan. Tetapi jika Anda masih menggunakan ORM untuk itu, ORM akan memaksa Anda untuk mengemas semuanya menjadi objek data. Yang terlepas dari tidak benar-benar berorientasi objek, sekali lagi bukan desain terbaik untuk beberapa kasus penggunaan.
Bagaimana jika saya hanya ingin memperbarui sebagian catatan? Mengapa saya membutuhkan representasi objek untuk semua catatan? Dll
Jadi solusi untuk itu adalah tidak menggunakan ORM untuk kasus penggunaan yang tidak cocok. Terapkan kasus penggunaan "secara alami" sebagaimana adanya, yang kadang-kadang tidak memerlukan "abstraksi" tambahan dari data itu sendiri (objek data) atau abstraksi atas "tabel" (repositori).
Memiliki objek data yang setengah terisi atau mengganti referensi objek dengan "id" adalah solusi terbaik, bukan desain yang baik, seperti yang Anda tunjukkan.
Angka 3 .: (memeriksa batasan)
Jika kegigihan tidak diabstraksikan, setiap use-case jelas dapat memeriksa kendala apa pun yang diinginkan dengan mudah. Persyaratan bahwa objek tidak tahu "repositori" sepenuhnya buatan dan bukan masalah teknologi.
Butir 5 .: (ORM)
Tidak, tidak. Ada banyak cara lain untuk bertahan. Masalahnya adalah bahwa ORM dipandang sebagai "solusi" untuk digunakan, selalu (setidaknya untuk database relasional). Mencoba menyarankan untuk tidak menggunakannya untuk beberapa kasus penggunaan dalam suatu proyek adalah sia-sia dan tergantung pada ORM itu sendiri kadang-kadang bahkan tidak mungkin, karena cache dan eksekusi yang terlambat kadang-kadang digunakan oleh alat-alat ini.
Pertanyaan umum 1 .: (transaksi)
Saya kira tidak ada solusi tunggal. Jika desain Anda berorientasi objek, akan ada metode "top" untuk setiap use case. Transaksi harus ada di sana.
Pembatasan lain sepenuhnya buatan.
Pertanyaan umum 2 .: (operasi massal)
Dengan ORM, Anda (untuk sebagian besar ORM yang saya tahu) dipaksa untuk melalui objek individual. Ini sama sekali tidak perlu dan mungkin bukan desain Anda jika tangan Anda tidak akan diikat oleh ORM.
Persyaratan untuk memisahkan "logika" dari SQL berasal dari ORM. Mereka harus mengatakan itu, karena mereka tidak dapat mendukungnya. Itu tidak secara inheren "buruk".
Ringkasan
Saya kira maksud saya adalah ORM tidak selalu merupakan alat terbaik untuk suatu proyek, dan bahkan jika itu, ORM sangat tidak mungkin menjadi yang terbaik untuk semua kasus penggunaan dalam suatu proyek.
Demikian pula, abstraksi dataobject-repositori dari DDD tidak selalu yang terbaik juga. Saya bahkan akan mengatakan lebih jauh, mereka jarang desain yang optimal.
Itu membuat kita tidak memiliki solusi satu ukuran untuk semua, jadi kita harus memikirkan solusi untuk setiap kasus penggunaan secara individual, yang bukan berita baik dan jelas membuat pekerjaan kita lebih sulit :)
sumber