Pendekatan DDD untuk operasi CRUD dasar dalam aplikasi domain-centric yang kompleks

9

Perusahaan saya sedang menulis ulang aplikasi web kami dari awal. Ini adalah aplikasi tingkat perusahaan besar dengan domain kompleks di industri keuangan.

Kami menggunakan ORM (kerangka kerja Entity) untuk kegigihan.

Intinya, setengah dari aplikasi kami berpusat di sekitar pengumpulan data mentah dari pengguna, menyimpannya, dan kemudian setengah dari aplikasi lain yang mengandung sebagian besar logika domain aktual kami mengambil data mentah itu untuk membuat gambar domain kami yang sangat berbeda dari yang asli input mentah, dan meneruskannya ke mesin calc, menjalankan calcs, dan memuntahkan hasil, yang kemudian ditampilkan kepada pengguna.

Dalam pendekatan DDD menggunakan lapisan, sepertinya operasi CRUD melewati lapisan domain. tetapi setidaknya dalam kasus kami, ini sepertinya tidak masuk akal.

Misalnya, ketika pengguna pergi ke layar edit untuk mengubah akun investasi, bidang pada layar adalah bidang yang tepat disimpan dalam database, bukan representasi domain yang digunakan nanti untuk perhitungan. Jadi mengapa saya akan memuat representasi domain dari akun investasi ketika layar edit membutuhkan representasi basis data (input mentah)?

Setelah pengguna mengklik "Selesai" pada layar akun investasi, dan POST dilakukan ke controller, controller sekarang memiliki cukup banyak representasi database yang tepat dari akun investasi yang perlu disimpan. Tetapi untuk beberapa alasan, saya seharusnya memuat representasi domain untuk membuat modifikasi alih-alih hanya memetakan model pengontrol langsung ke model database (model kerangka kerja Entity)?

Jadi pada intinya saya memetakan model data ke model domain, supaya bisa dipetakan kembali ke model data untuk bertahan. Bagaimana itu masuk akal?

wired_in
sumber

Jawaban:

9

Oke bayangkan Anda mengimplementasikan halaman pembuatan akun Anda memetakan pos form langsung ke objek EF yang kemudian disimpan ke db.

Lebih jauh kita berasumsi bahwa database memiliki berbagai batasan yang mencegah data yang salah dimasukkan. Akun selalu memiliki Pelanggan dll.

Segalanya tampak baik-baik saja. Tetapi kemudian bisnis membuat aturan baru.

  • Akun yang dibuat pada hari Kamis mendapatkan tingkat bunga bonus 2%. (anggap suku bunga adalah salah satu bidang akun)

Sekarang Anda harus meletakkan logika ini di suatu tempat dan Anda tidak memiliki objek domain untuk memasukkannya.

DDD mengasumsikan bahwa Anda akan selalu memiliki aturan semacam ini, dan Anda mungkin melakukannya. Membuat akun harus memiliki berbagai pemeriksaan, log audit, dll. Yang tidak hanya berupa 'tulis satu baris ke db'

Rencanakan domain Anda dengan asumsi tidak ada kegigihan atau pengontrol MVC dengan logika ekstra. Pastikan Anda menangkap semua persyaratan dan semuanya ada dalam model domain.

Ewan
sumber
3
Itu cara yang bagus untuk menjelaskannya. Saya benci menemukan aturan bisnis yang dicampur dengan detail DB. +1
candied_orange
Poin bagus, tetapi bagaimana jika aturan validasi ini hanya berlaku selama pembuatan dan pembaruan input pengguna? Kemudian setelah kita memiliki input pengguna, model yang dibuat saat menjalankan perhitungan adalah model yang sama sekali berbeda. Haruskah kita memiliki dua model domain untuk akun investasi? Satu untuk operasi CRUD input mentah untuk pengguna dan satu lagi ketika input tersebut digunakan untuk membuat model domain yang digunakan dalam perhitungan?
wired_in
membuat pertanyaan saya bingung. Anda harus memberikan contoh lengkap. Jika Anda memiliki logika domain, harus ada dalam objek domain. Itu tidak berarti Anda tidak dapat membuat objek domain lain nanti dari yang pertama
Ewan
Bayangkan mesin perhitungan yang rumit. Salah satu input yang diperlukan untuk menjalankan perhitungan adalah akun investasi, tetapi semua akun investasi adalah untuk mesin kalk adalah aliran pendapatan selama beberapa periode waktu. Model domain ini dari akun investasi sama sekali berbeda dari input mentah yang dimasukkan pengguna untuk akun investasi ini. Namun, ketika pengguna memasukkan input dasar seperti Nama, Nilai Saat Ini, dll. Masih harus ada logika validasi, tetapi seharusnya tidak ada hubungannya dengan model yang digunakan mesin kalk. Jadi, apakah ada dua model domain untuk akun investasi di sini?
wired_in
..... atau mungkin memiliki model akun investasi dalam domain terlalu banyak untuk operasi CRUD dan seharusnya hanya ada beberapa atribut validator yang digunakan atau sesuatu
wired_in
7

Bagaimana itu masuk akal?

Jawaban singkat: tidak .

Jawaban yang lebih panjang: pola kelas berat untuk mengembangkan model domain tidak berlaku untuk bagian-bagian solusi Anda yang hanya berupa basis data.

Udi Dahan memiliki pengamatan menarik yang dapat membantu memperjelas ini

Dahan menganggap bahwa suatu layanan harus memiliki semacam fungsi dan beberapa data. Jika tidak memiliki data, maka itu hanyalah sebuah fungsi. Jika semua yang dilakukannya adalah melakukan operasi CRUD pada data, maka itu adalah basis data.

Maksud dari model domain, bagaimanapun, adalah untuk memastikan bahwa semua pembaruan pada data mempertahankan invarian bisnis saat ini. Atau, dengan kata lain, model domain bertanggung jawab untuk memastikan bahwa database yang bertindak sebagai sistem catatan sudah benar.

Ketika Anda berhadapan dengan sistem CRUD, Anda biasanya bukan sistem catatan untuk data. Dunia nyata adalah buku catatan, dan basis data Anda hanyalah representasi cache lokal dari dunia nyata.

Misalnya, sebagian besar informasi yang muncul di profil pengguna, seperti alamat email, atau nomor identifikasi yang dikeluarkan pemerintah, memiliki sumber kebenaran yang hidup di luar bisnis Anda - itu adalah administrator surat orang lain yang menetapkan dan mencabut alamat email, bukan aplikasi Anda. Ini adalah pemerintah yang menetapkan SSN, bukan aplikasi Anda.

Jadi Anda biasanya tidak akan melakukan validasi domain pada data yang datang kepada Anda dari dunia luar; Anda mungkin memiliki pemeriksaan untuk memastikan bahwa data terbentuk dengan baik dan disanitasi dengan baik ; tetapi ini bukan data Anda - model domain Anda tidak mendapatkan veto.

Dalam pendekatan DDD menggunakan lapisan, sepertinya operasi CRUD melewati lapisan domain. tetapi setidaknya dalam kasus kami, ini sepertinya tidak masuk akal.

Itu tepat untuk kasus di mana database adalah buku catatan .

Ouarzy mengatakannya begini .

Bekerja pada banyak kode lawas, saya mengamati kesalahan umum untuk mengidentifikasi apa yang ada di dalam domain, dan apa yang ada di luar.

Aplikasi dapat dianggap CRUD hanya jika tidak ada logika bisnis di sekitar model data. Bahkan dalam kasus (jarang) ini, model data Anda bukan model domain Anda. Ini hanya berarti bahwa, karena tidak ada logika bisnis yang terlibat, kami tidak memerlukan abstraksi untuk mengelolanya, dan dengan demikian kami tidak memiliki model domain.

Kami menggunakan model domain untuk mengelola data yang berada di dalam domain; data dari luar domain sudah dikelola di tempat lain - kami hanya menyalin salinan.

Greg Young menggunakan sistem gudang sebagai ilustrasi utama solusi di mana buku catatan berada di tempat lain (yaitu: lantai gudang). Implementasi yang ia gambarkan sangat mirip dengan Anda - satu basis data logis untuk menangkap pesan yang diterima dari gudang, dan kemudian basis data logis terpisah yang menyimpan kesimpulan yang diambil dari analisis pesan tersebut.

Jadi mungkin kita memiliki dua konteks terbatas di sini? Masing - masing dengan model yang berbeda untukinvestment account

Mungkin. Saya enggan menandainya sebagai konteks terbatas, karena tidak jelas bagasi apa yang disertakan. Mungkin Anda memiliki dua konteks, mungkin satu konteks dengan perbedaan halus dalam bahasa di mana-mana yang belum Anda ambil.

Kemungkinan uji lakmus: berapa banyak pakar domain yang Anda perlukan dua pakar domain untuk membahas spektrum ini, atau hanya satu yang berbicara tentang komponen dengan cara yang berbeda. Pada dasarnya, Anda mungkin bisa menebak berapa banyak konteks terikat yang Anda miliki dengan menerapkan hukum Conway ke belakang.

Jika Anda mempertimbangkan konteks terikat untuk disejajarkan dengan layanan, mungkin lebih mudah: apakah Anda dapat menggunakan dua fungsi ini secara mandiri? Ya menyarankan dua konteks yang dibatasi; tetapi jika mereka perlu terus disinkronkan, maka mungkin itu hanya satu.

VoiceOfUnreason
sumber
Ya ada validasi dan logika default, tetapi itu hanya berlaku ketika membuat / memperbarui input mentah untuk akun investasi. Kemudian kami menggunakan model yang jauh lebih kaya untuk akun investasi ketika kami menggunakannya sebagai input ke mesin kalk. Jadi mungkin kita memiliki dua konteks terbatas di sini? Masing-masing dengan model berbeda untuk akun investasi '
wired_in
Saya baru saja kembali ke ini setelah beberapa tahun, dan komentar Anda beresonansi sekarang lebih dari sebelumnya karena suatu alasan. Ada banyak hal bagus di sini, tetapi bisakah Anda menjelaskan satu hal untuk saya? Anda berkata, "Inti dari model domain, bagaimanapun, adalah untuk memastikan bahwa semua pembaruan pada data mempertahankan invarian bisnis saat ini." Ini akan berlaku untuk bagian dari aplikasi kami yang menyimpan / memperbarui informasi. Bagian lainnya hanyalah mesin perhitungan. Dibutuhkan representasi data sebagai input dan mengeluarkan hasil. Apakah itu bukan bagian dari model domain? Karena itu tidak mempengaruhi data yang disimpan?
wired_in
2

Di domain Anda, Anda tidak perlu tahu bahwa basis datanya bahkan ada.

Domain Anda adalah tentang aturan bisnis. Hal-hal yang perlu bertahan ketika perusahaan yang membuat basis data Anda gulung tikar. Yaitu, jika Anda ingin perusahaan Anda bertahan. Sangat menyenangkan ketika aturan itu tidak peduli bahwa Anda telah mengubah cara Anda mempertahankan data.

Rincian basis data ada dan perlu ditangani. Mereka harus tinggal di tempat lain. Tempatkan mereka melintasi batas. Kontrol dengan cermat bagaimana Anda berkomunikasi melintasi batas itu atau itu bukan batas.

Paman Bob mengatakan ini tentang apa yang harus dimasukkan data Anda:

Biasanya data yang melintasi batas adalah struktur data sederhana. Anda dapat menggunakan struct dasar atau objek Transfer Data sederhana jika Anda mau. Atau datanya bisa berupa argumen dalam pemanggilan fungsi. Atau Anda bisa mengemasnya ke dalam hashmap, atau membuatnya menjadi sebuah objek.

Yang penting adalah bahwa struktur data yang terisolasi, sederhana, dilewatkan melintasi batas. Kami tidak ingin menipu dan melewati baris Entitas atau Database. Kami tidak ingin struktur data memiliki ketergantungan apa pun yang melanggar Aturan Ketergantungan.

[...] ketika kami meneruskan data melintasi batas, selalu dalam bentuk yang paling nyaman untuk lingkaran dalam.

Arsitektur Bersih

Dia juga menjelaskan bagaimana lapisan luar Anda seharusnya menjadi plugin untuk lapisan dalam Anda sehingga lapisan dalam tidak tahu ada lapisan luar.

Bersihkan lembar contekan arsitektur

Ikuti sesuatu seperti itu dan Anda akan memiliki tempat yang bagus untuk mengabaikan basis data di mana Anda dapat khawatir tentang aturan validasi input, aturan yang inputnya harus tetap dipertahankan, aturan untuk menjalankan perhitungan, aturan untuk mengirim hasil tersebut ke output apa pun. Sebenarnya lebih mudah untuk membaca kode semacam ini.

Entah itu atau Anda memutuskan bahwa domain Anda benar-benar hanya untuk memanipulasi database. Dalam hal ini bahasa domain Anda adalah SQL. Jika begitu baik tetapi jangan berharap implementasi Anda dari aturan bisnis untuk bertahan dalam perubahan dalam kegigihan. Anda akhirnya harus menulis ulang sepenuhnya.

candied_orange
sumber
Kami menggunakan ORM (Entity Framework), jadi basis data kami sudah diabstraksi, tetapi model data (kelas-kelas kerangka kerja Entitas) secara alami cukup banyak 1 banding 1 dengan tabel database. Masalahnya adalah bahwa di beberapa bagian aplikasi kita pengguna pada dasarnya hanya memperbarui model data (layar hanyalah daftar kotak teks di mana setiap kotak teks adalah bidang dalam database (model data).
wired_in
Jadi saya tidak melihat alasan untuk tidak hanya menggunakan representasi data mentah (model data) ketika melakukan operasi CRUD. Kami memiliki representasi domain kompleks yang digunakan untuk perhitungan, yang saya lihat sebagai model domain kami, tetapi saya tidak melihat mengapa saya memuat gambar itu di bagian CRUD dari aplikasi kami.
wired_in
Definisikan apa yang Anda maksud dengan "gunakan representasi data mentah". Data adalah input, data divalidasi sesuai dengan aturan domain, data tetap ada, data dihitung melawan, hasilnya adalah output untuk apa pun. Apakah saya melewatkan sesuatu?
candied_orange
Saya mencoba mengatakan bahwa data mentah yang kami dapatkan dari pengguna untuk akun investasi bukanlah bagaimana kami mewakili akun investasi itu di bagian utama aplikasi kami, seperti ketika digunakan untuk calcs. Misalnya, kami mungkin memiliki input boolean yang kami simpan di basis data yang disebut IsManagedAccount. Pengguna memasok kami dengan ini melalui tombol radio pada layar edit. Sehingga representasi dari basis data ke layar adalah 1 banding 1. Ketika kita membangun model domain kita nanti dalam aplikasi, kita mungkin memiliki kelas ManagedAccount, sehingga tidak ada properti boolean. Kedua struktur ini sangat berbeda.
wired_in
Jadi ketika pengguna hanya mengedit input mentah pada layar edit, mengapa saya memuat gambar domain dan kemudian menambahkan banyak kerumitan untuk memetakan kelas ManagedAccount yang diketik dengan sangat kuat kembali ke representasi datar yang hanya satu kelas dengan IsManagedAccount Properti?
wired_in
1

Menerapkan teori DDD:

Ada dua Konteks Terbatas dalam domain itu:

  • Perhitungan akun investasi. Model matematika akun investasi adalah salah satu elemen yang mungkin merupakan Agregat.
  • Keuangan Inti. Akun investasi klien adalah salah satu Entitas.

Setiap Bounded Context dapat memiliki desain arsitektur yang berbeda.

Contoh:

Akun Investasi Klien adalah Entitas (mungkin Agregat, tergantung pada domain) dan kegigihan data dilakukan melalui Entitas's Repository (RDB atau jenis DB lainnya seperti Database OO).

Tidak ada pendekatan DDD untuk operasi CRUD. Untuk membuat bidang DB diikat ke data objek, istirahat prinsip-prinsip desain.

Derek
sumber