Nilai yang Dihitung dan Bacaan Sederhana - Rasa sakit yang mengganggu untuk Desain Didorong Domain saya!

9

Masalah yang terus saya hadapi adalah bagaimana menangani nilai-nilai yang dikomputasi didorong oleh logika domain sementara masih bekerja secara efisien terhadap penyimpanan data.

Contoh:

Saya mengembalikan daftar Produk dari repositori saya melalui layanan. Daftar ini dibatasi oleh informasi pagination dari permintaan DTO yang dikirim oleh klien. Selain itu, DTO menetapkan parameter sortir (enum yang ramah-klien).

Dalam skenario sederhana, semuanya berfungsi dengan baik: layanan mengirimkan paging dan menyortir ekspresi ke repo dan repo mengeluarkan kueri yang efisien ke DB.

Namun, semua itu rusak ketika saya harus mengurutkan nilai yang dihasilkan dalam memori dari model domain saya. Misalnya kelas Produk memiliki metode IsExpired () yang mengembalikan bool berdasarkan logika bisnis. Sekarang saya tidak bisa mengurutkan dan halaman di tingkat repo - semua akan dilakukan dalam memori (tidak efisien) dan layanan saya harus tahu seluk-beluk kapan mengeluarkan params ini ke repo dan kapan melakukan sorting / paging diri.

Satu-satunya pola yang tampaknya masuk akal bagi saya adalah untuk menyimpan keadaan entitas di db (membuat IsExpired () bidang yang hanya dibaca dan memperbaruinya melalui logika domain sebelum menyimpan). Jika saya memisahkan logika ini menjadi repositori "baca model / dto" dan "pelaporan" yang terpisah, saya membuat model saya lebih anemia daripada yang saya inginkan.

BTW, setiap contoh saya telah melihat di luar sana untuk perhitungan seperti ini benar-benar bersandar pada pemrosesan dalam memori dan mengabaikan fakta bahwa itu jauh lebih efisien dalam jangka panjang. Mungkin saya terlalu dini mengoptimalkan, tapi itu tidak cocok dengan saya.

Saya ingin mendengar bagaimana orang lain berurusan dengan ini karena saya yakin itu biasa terjadi pada hampir proyek yang melibatkan DDD.

drogon
sumber

Jawaban:

3

Saya tidak berpikir bahwa memiliki dua model domain berbeda dari model data yang sama membuat domain Anda anemia. Model domain anemik adalah model di mana logika bisnis yang sering berubah disembunyikan dari domain dalam lapisan layanan (atau, lebih buruk, di lapisan UI).

Pemisahan model domain perintah dan kueri sering didukung dan memiliki akronim yang bagus yang dapat Anda gunakan di CQRS (Segregation Command Query Responsibility).

Menggunakan Pola Model Domain, Udi Dahan

Sementara saya "sukses" di masa lalu dalam menciptakan model objek tunggal persisten yang menangani kedua perintah dan kueri, seringkali sangat sulit untuk skala itu, karena setiap bagian dari sistem menarik model ke arah yang berbeda.

Ternyata pengembang sering mengambil persyaratan yang lebih berat daripada yang sebenarnya dibutuhkan bisnis. Keputusan untuk menggunakan entitas model domain untuk menunjukkan informasi kepada pengguna hanyalah contoh seperti itu.

[...]

Untuk diingat, praktik terbaik seputar penggunaan COM + memandu kami untuk membuat komponen terpisah untuk read-only dan untuk read-write logic. Inilah kita, satu dekade kemudian, dengan teknologi baru seperti Entity Framework, namun prinsip-prinsip yang sama terus berlaku.

CQRS dengan aktor Akka dan model domain fungsional, Debasish Ghosh

Greg Young telah menyampaikan beberapa sesi hebat tentang DDD dan CQRS. Pada tahun 2008 ia berkata "Model tunggal tidak dapat sesuai untuk pelaporan, pencarian dan perilaku transaksional". Kami memiliki setidaknya dua model - satu yang memproses perintah dan mengumpan perubahan ke model lain yang melayani permintaan dan laporan pengguna. Perilaku transaksional dari aplikasi akan dieksekusi melalui model agregat dan repositori yang kaya, sementara kueri langsung dilayani dari model data yang tidak dinormalisasi.

CQRS, Martin Fowler

Perubahan yang diperkenalkan CQRS adalah untuk membagi model konseptual menjadi model terpisah untuk pembaruan dan tampilan, yang masing-masing disebut sebagai Command dan Query mengikuti kosakata CommandQuerySeparation. Alasannya adalah bahwa untuk banyak masalah, terutama di domain yang lebih rumit, memiliki model konseptual yang sama untuk perintah dan permintaan mengarah ke model yang lebih kompleks yang tidak baik.

Singkatnya, ide Anda untuk memiliki model perintah menangani kedaluwarsa dan meneruskannya ke database benar-benar baik-baik saja. Bacalah artikel pertama di atas dan Anda akan melihat skenario serupa tetapi lebih kompleks.

pdr
sumber
2

SPESIFIKASI

Saya tahu Anda sudah menerima jawaban, tetapi, Anda bertanya tentang DDD, dan kecocokan persis untuk ini adalah apa yang disebut Evans sebagai 'spesifikasi':
tautan langsung buku google.
Jika tautan itu tidak berfungsi, periksa buku di hasil ini
Itu halaman 226 jika Anda memiliki buku itu.

Pada halaman 227 ada 3 kegunaan untuk spesifikasi: Validasi, Seletion, Membangun objek khusus baru. Milik Anda adalah 'seleksi' - IsExpired.

Hal lain tentang konsep 'specificaiton' adalah bahwa ia mengakui bahwa - demi efisiensi - Anda mungkin memerlukan satu versi kode untuk beroperasi pada objek dalam-memori, dan versi lain dari kode untuk secara efisien meminta repositori tanpa harus terlebih dahulu mendapatkan semua benda menjadi memori.

Dalam dunia yang sederhana, ini berarti menempatkan versi SQL di repositori Anda dan versi objek dalam model Anda, tentu saja yang memiliki kekurangan. Logikanya ada di 2 tempat (buruk, seseorang akan lupa untuk memperbarui tempat-tempat itu) dan ada logika domain di repositori Anda.

Jadi jawabannya adalah untuk meletakkan kedua set logika dalam spesifikasi. Versi dalam memori, jelas, tetapi versi repositori juga. Jika Anda menggunakan misalnya n-hibernate, Anda dapat menggunakan bahasa kueri bawaan untuk versi repositori.

Kalau tidak, Anda harus membuat metode repositori khusus untuk spesifikasi ini yang digunakan dari objek spesifikasi. Panggilan untuk kumpulan benda yang cocok dengan spesifikasi akan pergi melalui spesifikasi, bukan repositori. Dan setidaknya kode itu berteriak 'aku ada di 2 tempat, jangan lupa' ke pengelola masa depan. Ada contoh yang bagus di halaman 231-232 untuk menyelesaikan masalah yang sangat mirip.

Spesifikasi adalah kebocoran / kelesuan 'yang diizinkan' dari 'kemurnian' DDD. Masih mungkin tidak melayani kebutuhan Anda untuk berbagai keperluan. Misalnya, ORM mungkin menghasilkan SQL yang buruk; mungkin ada terlalu banyak pengkodean tambahan. Jadi Anda mungkin harus memanggil metode repositori sehingga hampir seperti menempatkan SQL dalam spesifikasi. Suatu hal yang buruk tentu saja. Tapi jangan lupa, program Anda harus bekerja - pada kecepatan yang masuk akal. Tidak harus memenangkan hadiah kemurnian DDD. Jadi kenyataan beralih datastore mungkin berarti pembedahan kuno sepanjang program. Juga hal yang buruk. Tapi tidak seburuk program yang lambat (alias SUCKing). Jika kehabisan kotak pada berbagai DB adalah kenyataan, jelas, Anda akan menduplikasi aturan bisnis untuk setiap datastore untuk setiap spesifikasi. Setidaknya Anda memiliki masalah dalam hal ini dan Anda dapat menggunakan pola strategi ketika Anda bertukar repositori. Tetapi jika Anda menggunakan DB tertentu sudah ingatYAGNI.

Mengenai CQRS: Kutipan Fowler oleh pdr di atas masih berlaku di sini: "memiliki model konseptual yang sama untuk perintah dan permintaan mengarah ke model yang lebih kompleks yang tidak baik" ... ... dan Anda mungkin perlu menggunakan CQRS atau serupa. Tetapi jauh lebih mahal dari sudut pandang pengembangan dan pemeliharaan. Jika Anda adalah vendor paket yang bersaing dengan yang lain, itu mungkin membayar. Jika Anda menulis aplikasi LOB khusus untuk satu pelanggan, memotret untuk kesempurnaan adalah pilihan yang buruk. Anda perlu memutuskan apakah nilai memiliki model yang sepenuhnya atau sebagian besar ganda layak dilakukan. Spesifikasiadalah kompromi yang baik karena memungkinkan Anda untuk membuat pemisahan ini hanya dalam satu bagian kecil dari program yang membutuhkannya, dengan kecepatan (pengembangan) dan kesederhanaan satu model. Semoga berhasil!

FastAl
sumber
Itu masuk akal. Saya pikir saya perlu menggigit peluru dan membaca buku Evans :-) Saya melihat sekarang bahwa memiliki pemahaman yang dangkal tentang konsep-konsep ini dapat benar-benar melumpuhkan Anda!
drogon
0

Saya kira saya akan mempertanyakan logika bisnis apa yang menentukan apakah Expired benar atau tidak. Bisakah logika ini dilakukan oleh permintaan sebagai model data berdiri? Jika demikian, dapatkah Anda membuat repositori Anda cukup pintar untuk menggunakan logika "isExpired" ketika Anda meminta Produk dengan cara tertentu? Jika tidak, mungkin Anda perlu menguji kembali model data Anda.

DDD tidak berarti bahwa repositori Anda harus bodoh - itu hanya berarti domain Anda perlu tahu cara berbicara dengan repositori Anda.

Matthew Flynn
sumber