Versi pendek
Alasan untuk DDD adalah bahwa Objek Domain adalah abstraksi yang harus memenuhi persyaratan domain fungsional Anda - jika Objek Domain tidak dapat dengan mudah memenuhi persyaratan tersebut, itu menunjukkan Anda mungkin menggunakan abstraksi yang salah.
Memberi Nama Objek Domain menggunakan Entity Nouns dapat menyebabkan objek-objek tersebut menjadi sangat erat satu sama lain dan menjadi objek "dewa" yang membengkak, dan mereka dapat memunculkan masalah seperti yang ada di pertanyaan ini seperti "Di mana tempat yang tepat untuk meletakkan Metode CreateOrder? "
Untuk membuatnya lebih mudah untuk mengidentifikasi Root Agregat 'kanan', pertimbangkan pendekatan berbeda di mana Objek Domain didasarkan pada persyaratan bisnis tingkat tinggi fungsional - yaitu memilih kata benda yang merujuk pada persyaratan fungsional dan / atau perilaku yang perlu dilakukan oleh pengguna sistem. melakukan.
Versi Panjang
DDD adalah pendekatan untuk Desain OO yang dimaksudkan untuk menghasilkan grafik Objek Domain di Lapisan Bisnis sistem Anda - Objek domain bertanggung jawab untuk memenuhi persyaratan Bisnis Tingkat Tinggi Anda, dan idealnya harus dapat mengandalkan Lapisan Data untuk hal-hal seperti kinerja dan integritas dari penyimpanan data persisten yang mendasarinya.
Cara lain untuk melihatnya adalah poin-poin penting dalam daftar ini
- Entity Nouns biasanya menyarankan atribut data.
- Domain Nouns harus menyarankan perilaku
- Pemodelan DDD dan OO berkaitan dengan abstraksi berdasarkan persyaratan fungsional dan domain inti / logika bisnis.
- Lapisan Logika Bisnis bertanggung jawab untuk memenuhi persyaratan domain tingkat tinggi
Salah satu kesalahpahaman umum tentang DDD adalah bahwa Objek Domain harus didasarkan pada beberapa "benda" fisik dunia nyata (yaitu beberapa kata benda yang dapat Anda tunjukkan di dunia nyata, dikaitkan dengan semua jenis data / properti), namun datanya / atribut dari hal-hal dunia nyata itu tidak selalu menjadi titik awal yang baik ketika mencoba untuk memenuhi persyaratan fungsional.
Tentu saja, Logika Bisnis harus menggunakan data ini, tetapi Objek Domain itu sendiri pada akhirnya harus berupa abstraksi yang mewakili persyaratan dan perilaku Domain fungsional.
Sebagai contoh; kata benda seperti Order
atau Customer
tidak menyiratkan perilaku apa pun, dan oleh karena itu umumnya abstraksi yang tidak membantu untuk merepresentasikan logika bisnis dan Objek Domain.
Saat mencari jenis abstraksi yang mungkin berguna untuk mewakili Logika Bisnis, pertimbangkan persyaratan umum yang mungkin Anda harapkan dipenuhi oleh sistem:
- Sebagai Tenaga Penjual, saya ingin Membuat Pesanan untuk Pelanggan Baru sehingga saya dapat menghasilkan faktur untuk Produk yang akan dijual dengan Harga dan Kuantitasnya.
- Sebagai Penasihat Layanan Pelanggan, saya ingin Membatalkan Pesanan yang Tertunda sehingga Pesanan tidak dipenuhi oleh Operator Gudang.
- Sebagai Penasihat Layanan Pelanggan, saya ingin Mengembalikan Baris Pesanan sehingga Produk dapat disesuaikan ke dalam Inventaris dan Pembayaran akan Dikembalikan melalui metode Pembayaran asli Pelanggan.
- Sebagai Operator Gudang, saya ingin melihat semua Produk dengan Pending Order dan informasi Pengiriman sehingga saya dapat memilih produk dan mengirimkannya melalui Kurir.
- dll.
Pemodelan Persyaratan Domain dengan Pendekatan DDD
Berdasarkan daftar di atas, pertimbangkan beberapa Objek Domain potensial untuk sistem Pesanan seperti itu:
SalesOrderCheckout
PendingOrdersStream
WarehouseOrderDespatcher
OrderRefundProcessor
Sebagai objek domain, ini mewakili abstraksi yang mengambil kepemilikan berbagai persyaratan domain perilaku; memang kata benda mereka memberi petunjuk kuat pada persyaratan fungsional spesifik yang mereka penuhi.
(Mungkin ada infrastruktur tambahan di sana juga seperti EventMediator
untuk menyampaikan pemberitahuan bagi pengamat yang ingin tahu kapan pesanan baru telah dibuat, atau kapan pesanan telah dikirim, dll).
Misalnya, SalesOrderCheckout
mungkin perlu menangani data tentang Pelanggan, Pengiriman dan Produk, namun tidak peduli dengan apa pun yang berkaitan dengan perilaku pesanan pengiriman, menyortir pesanan yang tertunda, atau mengeluarkan pengembalian uang.
Untuk SalesOrderCheckout
memenuhi persyaratan domainnya termasuk memberlakukan aturan-aturan bisnis tersebut seperti mencegah pelanggan memesan terlalu banyak barang, mungkin menjalankan beberapa validasi, dan mungkin meningkatkan pemberitahuan untuk bagian lain dari sistem - itu dapat melakukan semua hal itu tanpa harus bergantung pada apa pun dari benda-benda lainnya.
DDD menggunakan Entity Nouns untuk mewakili Objek Domain
Ada sejumlah bahaya potensial ketika merawat kata benda sederhana seperti Order
, Customer
dan Product
sebagai Objek Domain; di antara masalah-masalah itu adalah yang Anda singgung dalam pertanyaan:
- Jika suatu metode menangani suatu
Order
, a Customer
dan a Product
, objek Domain mana yang dimilikinya?
- Di mana Root Agregat untuk 3 Obyek itu?
Jika Anda memilih Entity Nouns untuk mewakili Objek Domain, sejumlah hal mungkin terjadi:
Order
, Customer
dan Product
berisiko tumbuh menjadi benda "dewa"
- Risiko berakhir dengan satu objek
Manager
dewa untuk mengikat semuanya.
- Objek-objek itu berisiko saling terkait erat satu sama lain - mungkin sulit untuk memenuhi persyaratan domain tanpa melewati
this
(atau self
)
- Risiko mengembangkan abstraksi "bocor" - yaitu objek domain yang diharapkan untuk mengekspos puluhan
get
/ set
metode yang melemahkan enkapsulasi (atau, jika Anda tidak melakukannya, maka beberapa programmer lain mungkin akan nanti ..).
- Risiko Objek Domain menjadi membengkak dengan campuran data bisnis yang kompleks (misalnya input data pengguna melalui UI) dan status sementara (misalnya 'riwayat' tindakan pengguna saat pesanan telah dimodifikasi).
DDD, Desain OO dan Model Biasa
Kesalahpahaman umum tentang DDD dan OO Design adalah bahwa model "polos" entah bagaimana 'buruk' atau 'anti-pola'. Martin Fowler menulis sebuah artikel yang menggambarkan Model Domain Anemik - tetapi ketika ia menjelaskan dalam artikel itu, DDD sendiri tidak boleh 'bertentangan' dengan pendekatan pemisahan bersih antara lapisan
"Perlu juga ditekankan bahwa menempatkan perilaku ke objek domain tidak boleh bertentangan dengan pendekatan solid menggunakan layering untuk memisahkan logika domain dari hal-hal seperti ketekunan dan tanggung jawab presentasi. Logika yang harus ada dalam objek domain adalah logika domain - validasi domain, perhitungan , aturan bisnis - apa pun yang Anda suka menyebutnya. "
Dengan kata lain, menggunakan Model biasa untuk menyimpan data bisnis yang ditransfer antara lapisan lain (misalnya model Pesanan yang dilewatkan oleh aplikasi pengguna saat pengguna ingin membuat pesanan baru) bukan hal yang sama dengan "Model Domain Anemik". model data 'biasa' seringkali merupakan cara terbaik untuk melacak data dan mentransfer data antar lapisan (seperti layanan web REST, toko persistensi, Aplikasi atau UI, dll).
Logika bisnis dapat memproses data dalam model-model tersebut dan dapat melacaknya sebagai bagian dari kondisi bisnis - tetapi tidak serta merta mengambil kepemilikan dari model-model tersebut.
Root Agregat
Melihat kembali pada contoh Domain Objects - SalesOrderCheckout
, PendingOrdersStream
, WarehouseOrderDespatcher
, OrderRefundProcessor
masih ada ada jelas Agregat Akar; tapi itu sebenarnya tidak masalah karena Objek Domain ini memiliki tanggung jawab yang sangat terpisah yang tampaknya tidak tumpang tindih.
Secara fungsional, tidak perlu bagi SalesOrderCheckout
untuk berbicara dengan PendingOrdersStream
karena pekerjaan mantan selesai ketika telah menambahkan pesanan baru ke Database; di sisi lain, PendingOrdersStream
dapat mengambil pesanan baru dari Database. Objek-objek ini sebenarnya tidak perlu berinteraksi satu sama lain secara langsung (Mungkin Mediator Peristiwa mungkin memberikan notifikasi di antara keduanya, tapi saya berharap setiap sambungan antara objek-objek ini menjadi sangat longgar)
Mungkin Agregat Root akan menjadi Kontainer IoC yang menyuntikkan satu atau lebih dari Objek Domain ke Pengendali UI, juga menyediakan infrastruktur lain seperti EventMediator
dan Repository
. Atau mungkin itu akan menjadi semacam Layanan Orkestra ringan yang berada di atas Lapisan Bisnis.
Akar Agregat tidak selalu perlu menjadi Object Domain. Demi menjaga Pemisahan Kekhawatiran antara objek Domain, umumnya merupakan hal yang baik ketika akar agregat adalah objek terpisah tanpa logika bisnis.
Apa kriteria untuk mendefinisikan agregat?
Mari kita kembali ke dasar-dasar buku biru besar:
Tujuannya adalah untuk mempertahankan invarian. Tapi itu juga untuk mengelola identitas lokal yang benar, yaitu mengidentifikasi objek yang tidak memiliki makna sendiri.
Order
dan secaraOrder line
definitif menjadi bagian dari gugus seperti itu. Sebagai contoh:Order
, akan membutuhkan penghapusan semua lini.Jadi di sini agregat penuh diperlukan untuk memastikan aturan konsistensi dan invarian.
Kapan harus berhenti?
Sekarang, Anda menjabarkan beberapa aturan bisnis, dan berpendapat bahwa untuk memastikannya, Anda harus mempertimbangkan pelanggan sebagai bagian dari agregat:
Tentu saja, mengapa tidak. Mari kita lihat implikasinya: pesanan akan selalu diakses melalui pelanggan. Apakah ini kehidupan nyata ? Ketika pekerja mengisi kotak untuk mengirimkan pesanan, apakah mereka perlu membaca kode batang pelanggan dan barcode pesanan untuk mengakses pesanan? Faktanya, secara umum, identitas suatu Order bersifat global, bukan lokal bagi pelanggan, dan independensi relatif ini menyarankan agar ia berada di luar agregat.
Selain itu, aturan bisnis ini lebih terlihat sebagai kebijakan: itu adalah keputusan sewenang-wenang perusahaan untuk menjalankan proses mereka dengan aturan ini. Jika aturan tidak dihormati, bos mungkin tidak senang, tetapi datanya tidak benar-benar tidak konsisten. Selain itu, dalam semalam "per pelanggan satu pesanan yang tidak terkirim pada satu waktu" dapat menjadi "sepuluh pesanan yang tidak terkirim per pelanggan" atau bahkan "secara terpisah dari pelanggan, ratusan pesanan yang tidak terkirim per gudang", sehingga agregat mungkin tidak lagi dibenarkan.
sumber
Sebelum Anda masuk terlalu jauh ke dalam lubang kelinci itu, Anda harus meninjau kembali diskusi Greg Young tentang konsistensi set , dan khususnya:
Karena dalam banyak kasus, jawaban yang tepat bukanlah mencoba mencegah hal yang salah terjadi, tetapi menghasilkan laporan pengecualian ketika mungkin ada masalah.
Tetapi, dengan anggapan bahwa banyak pesanan tidak terkirim adalah tanggung jawab yang signifikan bagi bisnis Anda ....
Ya, jika Anda ingin memastikan bahwa hanya ada satu pesanan yang tidak terkirim, maka harus ada agregat yang dapat melihat semua pesanan untuk pelanggan.
Agregat itu belum tentu merupakan agregat pelanggan .
Itu mungkin sesuatu seperti antrian pesanan, atau riwayat pesanan, di mana semua pesanan untuk pelanggan tertentu masuk ke antrian yang sama. Dari apa yang Anda katakan, itu tidak memerlukan semua data profil pelanggan, sehingga tidak boleh menjadi bagian dari agregat ini.
Ya, saat Anda benar-benar bekerja dengan lembar pemenuhan dan tarik, tampilan riwayat tidak terlalu relevan.
Tampilan histori, untuk menegakkan invarian Anda, hanya memerlukan id pesanan dan status pemrosesan saat ini. Itu tidak harus menjadi bagian dari agregat yang sama dengan urutan - ingat, batas agregat adalah tentang mengelola perubahan, bukan menyusun pandangan.
Jadi bisa jadi Anda menangani pesanan sebagai agregat, dan riwayat pesanan sebagai agregat terpisah, dan mengoordinasikan aktivitas di antara keduanya.
sumber
Anda telah membuat contoh orang jerami. Ini terlalu sederhana dan saya ragu itu mencerminkan sistem dunia nyata. Saya tidak akan memodelkan Entitas tersebut dan perilaku terkaitnya dengan cara yang Anda tentukan karena itu.
Kelas Anda perlu memodelkan keadaan pesanan dengan cara yang tercermin dalam beberapa agregat. Misalnya ketika pelanggan menempatkan sistem ke dalam keadaan di mana permintaan pesanan pelanggan perlu diproses, saya mungkin membuat agregat objek entitas domain yang disebut
CustomerOrderRequest
atauPendingCustomerOrder
atau bahkan adilCustomerOrder
, atau bahasa apa pun yang digunakan bisnis, dan itu bisa menyimpan pointer ke keduanya Pelanggan dan OrderLines dan kemudian memiliki metode seperticanCustomerCompleteOrder()
yang dipanggil dari lapisan layanan.Objek domain ini akan berisi logika bisnis untuk menentukan apakah pesanan itu valid atau tidak.
Jika pesanan itu valid dan diproses maka saya akan memiliki beberapa cara untuk mengalihkan objek ini ke objek lain yang mewakili pesanan yang diproses.
Saya pikir masalah dengan pemahaman Anda adalah bahwa Anda menggunakan contoh agregat yang terlalu disederhanakan. A
PendingOrder
dapat berupa agregat sendiri yang terpisah dariUndeliveredOrder
dan lagi-lagi terpisah dariDeliveredOrder
atauCancelledOrder
atau apa pun.sumber
Vaughn Vernon menyebutkan ini dalam bukunya "Implementing Domain-Driven Design" di awal Bab 7 (Layanan):
"Seringkali indikasi terbaik bahwa Anda harus membuat Layanan dalam model domain adalah ketika operasi yang Anda perlu lakukan terasa tidak pada tempatnya sebagai metode pada Agregat atau Objek Nilai".
Jadi, dalam hal ini mungkin ada layanan domain yang disebut "CreateOrderService" yang mengambil contoh Pelanggan dan daftar item untuk pesanan.
sumber