it-swarm-id.com

Apakah Agregat DDD benar-benar ide yang baik dalam Aplikasi Web?

Saya masuk ke Domain Driven Design dan beberapa konsep yang saya temui sangat masuk akal, tetapi ketika saya memikirkannya lebih banyak, saya harus bertanya-tanya apakah itu benar-benar ide yang bagus.

Konsep Agregat, misalnya masuk akal. Anda membuat domain kepemilikan kecil sehingga Anda tidak harus berurusan dengan seluruh model domain.

Namun, ketika saya memikirkan hal ini dalam konteks aplikasi web, kita sering menekan basis data untuk menarik sebagian kecil bagian data. Misalnya, sebuah halaman hanya dapat mencantumkan jumlah pesanan, dengan tautan untuk mengklik untuk membuka pesanan dan melihat nomor pesanannya.

Jika saya memahami Agregat dengan benar, saya biasanya akan menggunakan pola repositori untuk mengembalikan OrderAggregate yang akan berisi anggota GetAll, GetByID, Delete, dan Save. Ok, kedengarannya bagus. Tapi...

Jika saya memanggil GetAll untuk mendaftar semua pesanan saya, tampaknya bagi saya bahwa pola ini akan membutuhkan seluruh daftar informasi agregat untuk dikembalikan, menyelesaikan pesanan, memesan baris, dll ... Ketika saya hanya memerlukan sebagian kecil dari informasi itu (hanya informasi tajuk).

Apakah saya melewatkan sesuatu? Atau ada beberapa level optimasi yang akan Anda gunakan di sini? Saya tidak dapat membayangkan bahwa seseorang akan menganjurkan mengembalikan seluruh agregat informasi ketika Anda tidak membutuhkannya.

Tentu saja, orang dapat membuat metode pada repositori Anda seperti GetOrderHeaders, tetapi itu tampaknya mengalahkan tujuan menggunakan pola seperti repositori.

Adakah yang bisa menjelaskan ini untuk saya?

EDIT:

Setelah penelitian lebih lanjut, saya pikir pemutusan di sini adalah bahwa pola Repositori murni berbeda dari apa yang kebanyakan orang pikirkan tentang Repositori.

Fowler mendefinisikan repositori sebagai penyimpan data yang menggunakan semantik koleksi, dan umumnya disimpan dalam memori. Ini berarti membuat seluruh grafik objek.

Evans mengubah Repositori untuk memasukkan Agregat Root, dan dengan demikian repositori diamputasi untuk hanya mendukung objek dalam Agregat.

Kebanyakan orang tampaknya menganggap repositori sebagai Objek Akses Data yang dimuliakan, di mana Anda hanya membuat metode untuk mendapatkan data apa pun yang Anda inginkan. Itu tampaknya tidak menjadi maksud seperti yang dijelaskan dalam Pola Arsitektur Aplikasi Perusahaan Fowler.

Yang lain lagi menganggap repositori sebagai abstraksi sederhana yang digunakan terutama untuk membuat pengujian dan ejekan lebih mudah, atau untuk memisahkan kegigihan dari sisa sistem.

Saya kira jawabannya adalah bahwa ini adalah konsep yang jauh lebih kompleks daripada yang saya pikirkan sebelumnya.

43
Erik Funkenbusch

Jangan gunakan Model Domain Anda dan agregat untuk kueri.

Sebenarnya, apa yang Anda tanyakan adalah pertanyaan yang cukup umum bahwa seperangkat prinsip dan pola telah ditetapkan untuk menghindari hal itu. Ini disebut CQRS .

31
quentin-starin

Saya berjuang, dan masih berjuang, dengan cara terbaik menggunakan pola repositori dalam Desain Domain Driven. Setelah menggunakannya sekarang untuk pertama kalinya, saya menemukan praktik berikut:

  1. Repositori harus sederhana; itu hanya bertanggung jawab untuk menyimpan objek domain dan mengambilnya. Semua logika lain harus di objek lain, seperti pabrik dan layanan domain.

  2. Repositori berperilaku seperti koleksi seolah-olah itu adalah kumpulan memori dari akar agregat.

  3. Repositori bukan DAO generik, masing-masing repositori memiliki antarmuka yang unik dan sempit. Repositori sering memiliki metode Finder khusus yang memungkinkan Anda untuk mencari koleksi dalam hal domain (misalnya: beri saya semua pesanan terbuka untuk pengguna X). Repositori itu sendiri dapat diimplementasikan dengan bantuan DAO generik.

  4. Idealnya metode Finder hanya akan mengembalikan akar agregat. Jika itu tidak efisien, ia juga dapat mengembalikan objek nilai hanya baca daripada berisi apa yang Anda butuhkan (meskipun ini merupakan nilai tambah jika objek nilai ini juga dapat dinyatakan dalam domain). Sebagai upaya terakhir repositori juga dapat digunakan untuk mengembalikan himpunan bagian atau koleksi himpunan bagian dari agregat root.

  5. Pilihan seperti ini bergantung pada teknologi yang digunakan, karena Anda perlu menemukan cara untuk paling efisien mengekspresikan model domain Anda dengan teknologi yang digunakan.

8
Kdeveloper

Saya tidak berpikir metode GetOrderHeaders Anda mengalahkan tujuan repositori sama sekali.

DDD prihatin (antara lain) dengan memastikan bahwa Anda mendapatkan apa yang Anda butuhkan melalui agregat root (misalnya, Anda tidak akan memiliki Repositori OrderDetailsRepository), tetapi DDD tidak membatasi Anda dengan cara yang Anda sebutkan.

Jika OrderHeader adalah konsep Domain, maka Anda harus mendefinisikannya dan memiliki metode penyimpanan yang sesuai untuk mengambilnya. Pastikan saja Anda melakukan root agregat yang benar saat melakukannya.

6
Eric King

Penggunaan DDD saya mungkin tidak dianggap DDD "murni" tetapi saya telah mengadaptasi strategi dunia nyata berikut menggunakan DDD terhadap penyimpanan data DB.

  • Root agregat memiliki repositori terkait
  • Repositori terkait hanya digunakan oleh root agregat itu (tidak tersedia untuk umum)
  • Repositori dapat berisi panggilan permintaan (mis. GetAllActiveOrders, GetOrderItemsForOrder)
  • Layanan memperlihatkan subset publik dari repositori dan operasi non-kasar lainnya (mis. Mentransfer Uang dari satu rekening bank ke yang lain, LoadById, Cari/Temukan, BuatEntitas, dll.).
  • Saya menggunakan Root -> Layanan -> tumpukan Repositori. Layanan DDD hanya dianggap digunakan untuk apa pun yang tidak dapat dijawab oleh Entitas (mis. LoadById, TransferMoneyFromAccountToAccount), tetapi di dunia nyata saya cenderung juga tetap menggunakan layanan terkait CRUD lainnya (Simpan, Hapus, Pertanyaan) meskipun root harus bisa "menjawab/melakukan" ini sendiri. Perhatikan bahwa tidak ada yang salah dengan memberikan entitas akses ke layanan root agregat lain! Namun, ingat Anda tidak akan memasukkan dalam layanan (GetOrderItemsForOrder) tetapi akan memasukkan itu dalam repositori sehingga Agregat Root dapat memanfaatkannya. Perhatikan bahwa suatu layanan tidak boleh mengekspos kueri terbuka seperti yang dapat dilakukan repositori.
  • Saya biasanya mendefinisikan Repositori secara abstrak dalam model domain (melalui antarmuka) dan memberikan implementasi konkret yang terpisah. Saya sepenuhnya mendefinisikan layanan dalam model domain yang menyuntikkan dalam repositori beton untuk penggunaannya.

** Anda tidak perlu mengembalikan seluruh agregat. Namun, jika Anda menginginkan lebih, Anda harus menanyakan root, bukan layanan atau repositori lain. Ini adalah pemuatan malas dan dapat dilakukan secara manual dengan pemuatan malas orang miskin (menyuntikkan repositori/layanan yang sesuai ke root) atau menggunakan dan ORM yang mendukung ini.

Dalam contoh Anda, saya mungkin akan menyediakan panggilan repositori yang hanya membawa header pesanan jika saya ingin memuat detail pada panggilan terpisah. Perhatikan bahwa dengan memiliki "OrderHeader" kami sebenarnya memperkenalkan konsep tambahan ke dalam domain.

4
Mike Rowley

Model domain Anda berisi logika bisnis Anda dalam bentuk yang paling murni. Semua hubungan dan operasi yang mendukung operasi bisnis. Apa yang Anda lewatkan dari peta konseptual Anda adalah gagasan Lapisan Layanan Aplikasi lapisan layanan melingkari model domain dan memberikan tampilan yang disederhanakan dari domain bisnis (proyeksi jika Anda mau) yang memungkinkan model Domain untuk berubah sesuai kebutuhan tanpa secara langsung memengaruhi aplikasi menggunakan lapisan layanan.

Melangkah lebih jauh Gagasan agregat adalah bahwa ada satu objek, akar agregat, yang bertanggung jawab untuk menjaga konsistensi agregat. Dalam contoh Anda, pesanan akan bertanggung jawab untuk memanipulasi garis pesanannya.

Sebagai contoh Anda, lapisan layanan akan memaparkan operasi seperti GetOrdersForCustomer yang hanya akan mengembalikan apa yang diperlukan untuk melihat daftar ringkasan pesanan (seperti Anda menyebutnya OrderHeaders).

Akhirnya, pola Repositori tidak hanya koleksi, tetapi juga memungkinkan untuk permintaan deklaratif. Dalam C # Anda dapat menggunakan LINQ sebagai Obyek Kueri , atau sebagian besar O/RM lainnya menyediakan spesifikasi Obyek Kueri juga.

Repositori memediasi antara domain dan lapisan pemetaan data, bertindak seperti kumpulan objek domain dalam memori. Objek Klien membuat spesifikasi permintaan secara deklaratif dan mengirimkannya ke Repositori untuk kepuasan. (dari halaman Repositori Fowler )

Melihat bahwa Anda dapat membuat kueri terhadap repositori, masuk akal juga untuk memberikan metode kenyamanan yang menangani kueri umum. Yaitu. jika Anda hanya ingin tajuk pesanan Anda, Anda bisa membuat kueri yang hanya mengembalikan tajuk dan memaparkannya dari metode kenyamanan di repositori Anda.

Semoga ini bisa membantu memperjelas hal-hal.

3
Michael Brown

Saya tahu ini adalah pertanyaan lama, tetapi saya tampaknya memiliki jawaban yang berbeda.

Ketika saya membuat Repositori, biasanya ada beberapa di-cache query.

Fowler mendefinisikan repositori sebagai penyimpan data yang menggunakan semantik koleksi, dan umumnya disimpan dalam memori. Ini berarti membuat seluruh grafik objek.

Simpan repositori itu di ram server Anda. Mereka tidak hanya melewati objek ke database!

Jika saya dalam aplikasi web dengan pesanan daftar halaman, yang dapat Anda klik untuk melihat detailnya, kemungkinan saya ingin halaman daftar pesanan saya memiliki detail tentang pesanan (ID, Nama, Jumlah, Tanggal) untuk membantu pengguna memutuskan mana yang ingin mereka lihat.

Pada titik ini Anda memiliki dua opsi.

  1. Anda dapat meminta basis data dan menarik kembali apa yang Anda butuhkan untuk membuat daftar, lalu meminta lagi untuk menarik setiap detail yang perlu Anda lihat pada halaman detail.

  2. Anda dapat membuat 1 kueri yang menarik kembali semua informasi dan menyimpannya. Pada permintaan halaman berikutnya Anda membaca dari ram server bukan dari database. Jika pengguna menekan balik atau memilih halaman berikutnya Anda masih melakukan nol perjalanan ke database.

Pada kenyataannya bagaimana Anda menerapkannya hanya itu, dan detail implementasi. Jika pengguna terbesar saya memiliki 10 pesanan, saya mungkin ingin menggunakan opsi 2. Jika saya berbicara 10.000 pesanan maka opsi 1 diperlukan. Dalam kedua kasus di atas dan dalam banyak kasus lain saya ingin repositori menyembunyikan detail implementasi itu.

Ke depan jika saya mendapatkan tiket untuk memberi tahu pengguna berapa banyak yang telah mereka belanjakan untuk pesanan ( data gabungan ) pada bulan lalu di halaman daftar pesanan, apakah saya lebih suka menulis logika untuk menghitung bahwa dalam SQL dan melakukan perjalanan pulang pergi ke DB atau apakah Anda lebih suka menghitungnya menggunakan data yang sudah ada di server ram?

Dalam pengalaman saya, agregat domain menawarkan manfaat besar.

  • Mereka adalah menggunakan kembali kode bagian besar yang benar-benar berfungsi.
  • Mereka menyederhanakan kode dengan menjaga logika bisnis Anda tepat di lapisan inti daripada harus menelusuri lapisan infrastruktur untuk mendapatkan server sql untuk melakukannya.
  • Mereka juga dapat secara dramatis mempercepat waktu respons Anda dengan mengurangi jumlah pertanyaan yang perlu Anda buat karena Anda dapat dengan mudah menyimpannya.
  • SQL yang saya tulis sering jauh lebih mudah dikelola karena saya sering hanya meminta semuanya dan menghitung sisi server.
0
WhiteleyJ