Bagaimana seharusnya kita membuat akar agregat baru dalam arsitektur cqrs? Dalam contoh ini saya ingin membuat AR2 root agregat baru yang menyimpan referensi ke AR1 pertama.
Saya membuat AR2 menggunakan metode AR1 sebagai titik awal. Sejauh ini saya melihat beberapa opsi:
- Metode di dalam AR1
createAr2RootOpt1
saya bisa memanggilnew AR2()
dan menyimpan objek ini ke db imediatelly menggunakan layanan domain yang memiliki akses ke repositori. Saya bisa memancarkan event di root agregat pertama misalnya.
SholdCreateAR2Event
dan kemudian memiliki stateless saga yang bereaksi pada ini dan mengeluarkan perintahCreateAR2Command
yang kemudian ditangani dan benar-benar menciptakan AR2 dan memancarkanAR2CreatedEvent
. Dalam hal menggunakan sumber acaraSholdCreateAR2Event
tidak akan disimpan di toko peristiwa, karena itu tidak mempengaruhi keadaan akar agregat pertama. (Atau haruskah kita menyimpan ini di toko acara?)class AR1{ Integer id; DomainService ds; //OPTION 1 void createAr2RootOpt1(){ AR2 ar2 = new AR2(); ds.saveToRepo(ar2); } //OPTION 2 void createAr2RootOpt2(){ publishEvent(new SholdCreateAR2Event()); //we don't need this event. Shoud it still be preserved in event store? } } class AR2{ Integer id; Integer ar1Id; void handle(CreateAR2Command command){ //init this AR with values and save publishEvent(AR2CreatedEvent()); //used for projections afterwards and saved inside AR2 event store } } class Saga{ void handle(SholdCreateAR2Event ev){ emitCommand(new CreateAR2Command()); } }
Mana cara yang lebih tepat untuk melakukan ini?
sumber
AR1WasCreated
? Haruskah begituAR2WasCreated
? Juga, jika saya menggunakan logika Anda, saya memancarkan acaraAR2WasCreated
sebelum itu benar-benar dibuat? Dan menyimpan acara ini di dalam log peristiwa AR1 tampaknya bermasalah, karena saya sebenarnya tidak membutuhkan data ini di dalam AR1 (tidak mengubah apa pun di dalam AR1).AR1WasCreated
-> SAGA (memiliki aturan jika A1 dibuat lalu buat A2) ->CreateAR2Command
->AR2WasCreated
.Pola penciptaannya aneh .
Udi Dahan memiliki beberapa hal berguna untuk dikatakan tentang masalah umum: Jangan Membuat Agregat Roots . Poin dasarnya adalah agregat itu tidak muncul begitu saja, dan ada bahasa domain yang menjelaskan bagaimana mereka muncul, yang harus ditangkap dalam model domain Anda.
Di mana ia cenderung menjadi bengkok adalah bahwa entitas dalam model domain Anda yang memproses perintah bukanlah entitas yang akan dimodifikasi oleh transaksi. Itu tidak salah; itu hanya aneh (dibandingkan dengan kasus di mana Anda meminta entitas untuk memodifikasi sendiri.
Pendekatan kedua Anda juga OK. "Acara yang kami angkat tanpa benar-benar menyimpan ke database" kadang-kadang disebut sebagai "peristiwa domain"
Gagasan dasarnya adalah bahwa, dalam transaksi yang sama, penangan perintah meningkatkan peristiwa, yang bergerak di sepanjang bus ke penangan peristiwa yang memungkinkan agregat kedua untuk membuat sendiri. Anda mendapatkan kohesi kode yang agak lebih baik, mungkin.
Catatan: dalam sistem sumber acara, Anda biasanya tidak menggunakan acara seperti ini.
Catatan: nama acara biasanya dalam bentuk lampau - ShouldCrateAR2 memiliki ejaan yang salah.
Ya, jika Anda hanya melempar acara ke bus sinkron untuk menjalankan kode jarak jauh, maka Anda tidak boleh menyimpan acara itu dalam buku catatan. Ini hanya detail implementasi pada skala ini.
Hindari mengubah dua aliran acara yang berbeda dalam transaksi yang sama. Jika kreasi ini juga mewakili perubahan ke AR1, maka jawaban yang biasa adalah memodifikasi AR1 dalam transaksi ini, dengan pelanggan asinkron ke peristiwa-peristiwa yang bertanggung jawab untuk menjalankan perintah untuk membuat AR2.
Penanganan perintah idempoten banyak membantu di sini.
sumber
AR1.doSmthn(AR2 param)
karena setiap proyeksi baca yang saya buat tidak memiliki data lengkap yang saya butuhkan (hanya AR2 yang memiliki data lengkap).