Bagaimana cara membuat root agregat baru di CQRS?

10

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:

  1. Metode di dalam AR1 createAr2RootOpt1saya bisa memanggil new AR2()dan menyimpan objek ini ke db imediatelly menggunakan layanan domain yang memiliki akses ke repositori.
  2. Saya bisa memancarkan event di root agregat pertama misalnya. SholdCreateAR2Eventdan kemudian memiliki stateless saga yang bereaksi pada ini dan mengeluarkan perintah CreateAR2Commandyang kemudian ditangani dan benar-benar menciptakan AR2 dan memancarkan AR2CreatedEvent. Dalam hal menggunakan sumber acara SholdCreateAR2Eventtidak 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?

Bojan Vukasovic
sumber

Jawaban:

2

Saya pikir opsi itu tidak. 2 adalah solusinya, dengan modifikasi kecil tapi penting: AR1tidak boleh memancarkan suatu acara yang tujuannya adalah untuk menciptakannya AR2, melainkan memancarkan suatu AR1WasCreatedperistiwa. Acara ini harus tetap ada di toko acara, karena merupakan acara penting yang menandai kelahiran AR1. Kemudian, Sagalistent whould untuk AR1WasCreatedacara dan menghasilkan perintah untuk membuat AR2: CreateAR2Command.

Opsi no.1 sangat salah. Anda tidak boleh menyuntikkan layanan domain semacam itu ke dalam Aggregate. Aggregatesharus murni, tanpa efek samping lain dari generasi peristiwa.

PS Saya tidak pernah memancarkan peristiwa dari konstruktor Aggregatekarena ada perbedaan antara membuat instance objek (dalam arti bahasa pemrograman) dan penciptaan (kelahiran jika Anda mau) dari sebuah Aggregate. Saya memancarkan acara hanya dari handlemetode (saat menangani a command).

Constantin Galbenu
sumber
Apa maksudmu AR1WasCreated? Haruskah begitu AR2WasCreated? Juga, jika saya menggunakan logika Anda, saya memancarkan acara AR2WasCreatedsebelum 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).
Bojan Vukasovic
Oke, 3 tahun kemudian. Kelanjutannya AR1WasCreated-> SAGA (memiliki aturan jika A1 dibuat lalu buat A2) -> CreateAR2Command-> AR2WasCreated.
Bojan Vukasovic
@BojanVukasovic Saya senang itu berhasil seperti yang saya tulis :)
Constantin Galbenu
2

Bagaimana seharusnya kita membuat akar agregat baru dalam arsitektur cqrs?

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.

Dalam hal menggunakan sumber acara, ShouldCreateAR2Event tidak akan disimpan di toko peristiwa, karena itu tidak mempengaruhi keadaan akar agregat pertama.

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.

Atau haruskah kita menyimpan ini di event store?

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.

VoiceOfUnreason
sumber
Terima kasih atas jawabannya. Satu hal lagi yang tidak 100% jelas - nanti jika saya harus menggunakan AR2 sebagai argumen untuk AR1 bagaimana saya harus lulus ini - karena CQRS menyatakan bahwa AR hanya boleh digunakan untuk menulis dan tidak query. Tapi saya tidak punya pilihan selain menggunakan AR1.doSmthn(AR2 param)karena setiap proyeksi baca yang saya buat tidak memiliki data lengkap yang saya butuhkan (hanya AR2 yang memiliki data lengkap).
Bojan Vukasovic
> "Ya, jika Anda hanya melempar sebuah peristiwa ke bus sinkron untuk menjalankan kode jarak jauh, maka Anda seharusnya tidak menyimpan peristiwa itu dalam buku catatan." Saya pikir menyimpannya memiliki nilai nyata karena Anda tahu bahwa prosesnya dimulai untuk sesuatu terjadi, Anda sekarang juga dapat melacak apakah ini benar-benar selesai. Tapi saya kira itu tergantung pada use case
Chaosekie