Ada tampaknya tak berujung kebingungan tentang apakah perintah yang harus atau tidak harus kembali nilai-nilai. Saya ingin tahu jika kebingungan hanya karena peserta tidak menyatakan konteks atau keadaan.
Berikut ini adalah contoh-contoh dari kebingungan...
Udi Dahan kata perintah "tidak kembali kesalahan ke klien," tapi dalam artikel yang sama ia menunjukkan diagram di mana perintah memang kembali kesalahan ke klien.
Microsoft Press Toko pasal serikat "perintah...doesn't kembali respon" tapi kemudian pergi untuk memberikan ambigu hati-hati:
Sebagai pengalaman medan tumbuh di sekitar CQRS, beberapa praktik-praktik konsolidasi dan cenderung menjadi praktik terbaik. Sebagian bertentangan dengan apa yang baru saja kita menyatakan... itu adalah pandangan umum hari ini untuk berpikir bahwa kedua perintah handler dan aplikasi perlu tahu bagaimana transaksional operasi berjalan. Hasil yang harus diketahui...
Nah, lakukan perintah penangan kembali nilai-nilai atau tidak?
Mengambil isyarat dari Jimmy Bogard's "CQRS Mitos," saya pikir jawabannya(s) untuk pertanyaan ini tergantung pada apa yang terprogram/kontekstual "kuadran" anda berbicara tentang:
+-------------+-------------------------+-----------------+
| | Real-time, Synchronous | Queued, Async |
+-------------+-------------------------+-----------------+
| Acceptance | Exception/return-value* | <see below> |
| Fulfillment | return-value | n/a |
+-------------+-------------------------+-----------------+
Perintah "Penerimaan" sebagian besar mengacu pada validasi. Agaknya hasil validasi harus diberikan serentak kepada pemanggil, apakah atau tidak perintah "pemenuhan" adalah sinkron atau antri.
Namun, tampaknya banyak praktisi don't melakukan validasi dari dalam command handler. Dari apa yang saya've melihat, itu adalah baik karena (1) mereka've sudah menemukan cara yang fantastis untuk menangani validasi pada lapisan aplikasi (yaitu ASP.NET MVC controller memeriksa valid negara melalui data anotasi) atau (2) arsitektur adalah di tempat yang mengasumsikan perintah dikirimkan ke (keluar dari proses) bus atau antrian. Yang terakhir ini bentuk asynchrony umumnya don't menawarkan sinkron validasi semantik atau interface.
Singkatnya, banyak desainer mungkin ingin command handler untuk memberikan hasil validasi sebagai (sinkron) nilai kembali, tetapi mereka harus hidup dengan pembatasan dari mereka asynchrony alat-alat yang mereka gunakan.
Mengenai "pemenuhan" perintah, klien yang mengeluarkan perintah mungkin perlu tahu scope_identity untuk yang baru dibuat catatan atau mungkin kegagalan informasi - seperti "akun tekor."
Dalam real-time setting tampaknya bahwa nilai kembali yang paling masuk akal; pengecualian tidak boleh digunakan untuk berkomunikasi bisnis yang berhubungan dengan kegagalan hasil. Namun, dalam "antrian" konteks...kembali nilai-nilai tentu tidak masuk akal.
Ini adalah di mana semua kebingungan yang mungkin bisa dirangkum:
Banyak (?) CQRS praktisi menganggap mereka akan sekarang, atau di masa depan, menggabungkan asynchrony framework atau platform (bus atau antrian) dan dengan demikian menyatakan bahwa perintah penangan tidak memiliki nilai kembali. Namun, beberapa praktisi tidak punya niat untuk menggunakan event-driven konstruksi, dan sehingga mereka akan mendukung perintah penangan yang (serentak) kembali nilai-nilai.
Jadi, misalnya, saya percaya sinkron (request-response) konteks diasumsikan ketika Jimmy Bogard yang disediakan ini contoh perintah interface:
public interface ICommand<out TResult> { }
public interface ICommandHandler<in TCommand, out TResult>
where TCommand : ICommand<TResult>
{
TResult Handle(TCommand command);
}
Nya Mediatr produk adalah, setelah semua, dalam memori alat. Mengingat semua ini, saya pikir alasan Jimmy hati-hati mengambil waktu untuk menghasilkan kekosongan kembali dari command tidak karena "perintah penangan tidak harus kembali nilai-nilai," tetapi bukan karena ia hanya ingin Mediator kelas untuk memiliki antarmuka yang konsisten:
public interface IMediator
{
TResponse Request<TResponse>(IQuery<TResponse> query);
TResult Send<TResult>(ICommand<TResult> query); //This is the signature in question.
}
...meskipun tidak semua perintah memiliki nilai yang berarti untuk kembali.
Aku benar menangkap mengapa ada kebingungan tentang topik ini? Apakah ada sesuatu yang saya'm hilang?
Mengikuti saran di Menanggulangi Kompleksitas dalam CQRS oleh Vladik Khononov menunjukkan perintah penanganan dapat kembali informasi yang berkaitan dengan hasilnya.
Tanpa melanggar [CQRS] prinsip-prinsip, perintah dapat dengan aman kembali data-data sebagai berikut:
- hasil Eksekusi: keberhasilan atau kegagalan;
- pesan Galat atau kesalahan validasi, dalam kasus kegagalan;
- agregat baru nomor versi, dalam hal keberhasilan;
informasi Ini akan secara dramatis meningkatkan pengalaman pengguna dari sistem anda, karena:
- Anda tidak perlu jajak pendapat sumber eksternal untuk eksekusi perintah hasilnya, anda memilikinya sekarang juga. Hal ini menjadi sepele untuk memvalidasi perintah, dan untuk mengembalikan pesan kesalahan.
- Jika anda ingin me-refresh data yang ditampilkan, anda dapat menggunakan agregat baru versi untuk menentukan apakah melihat model yang mencerminkan eksekusi perintah atau tidak. Tidak ada lagi menampilkan data basi.
Daniel Whittaker advokat kembali "umum hasil" obyek dari command handler yang berisi informasi ini.
Nah, apakah perintah penangan kembali nilai-nilai atau tidak?
Mereka tidak harus kembali Data Bisnis, hanya meta data (mengenai keberhasilan atau kegagalan mengeksekusi perintah). CQRS
adalah CQS diambil ke tingkat yang lebih tinggi. Bahkan jika anda akan mematahkan murni's aturan dan kembali sesuatu, apa yang akan anda kembali? Di CQRS command handler adalah metode aplikasi layanan
yang memuat agregat
kemudian memanggil metode pada agregat
kemudian berlanjut dengan agregat
. Yang berniat command handler adalah untuk memodifikasi agregat
. Anda tidak't tahu apa yang harus mengembalikan itu akan menjadi independen dari pemanggil. Setiap perintah handler pemanggil/klien ingin tahu sesuatu tentang negara baru.
Jika perintah eksekusi yang menghalangi (alias sinkron) maka semua yang anda akan perlu untuk mengetahui apakah jika perintah berhasil dijalankan atau tidak. Kemudian, dalam lapisan yang lebih tinggi, anda akan query yang tepat hal yang anda perlu tahu tentang aplikasi baru's negara menggunakan query-model yang paling sesuai dengan kebutuhan anda.
Berpikir sebaliknya, jika anda kembali sesuatu dari command handler anda memberikan dua tanggung jawab: 1. mengubah agregat negara dan 2. query membaca beberapa model.
Mengenai perintah validasi, setidaknya ada dua jenis perintah validasi:
Namun, jika kita pergi beberapa tingkat atas, di Presentation layer(yaitu
ISTIRAHATendpoint), klien dari
lapisan Aplikasi`, kita bisa mengembalikan apa-apa dan kami tidak akan' melanggar aturan karena endpoint dirancang setelah penggunaan kasus-kasus, anda tahu persis apa yang anda inginkan untuk kembali setelah perintah ini dijalankan, dalam setiap use case.
CQRS dan CQS seperti microservices dan kelas dekomposisi: gagasan utama adalah sama ("cenderung kecil kohesif modul"), tapi mereka berbohong pada berbagai tingkat semantik.
Titik CQRS adalah untuk membuat menulis/membaca model pemisahan; seperti tingkat rendah rincian seperti kembali nilai dari metode tertentu adalah benar-benar tidak relevan.
Memperhatikan berikut Fowler's quote:
perubahan yang CQRS memperkenalkan adalah untuk membagi bahwa model konseptual ke dalam model terpisah untuk update dan tampilan, yang ia sebut sebagai Perintah dan Permintaan masing-masing berikut kosakata CommandQuerySeparation.
Ini adalah tentang model, bukan metode.
Command handler mungkin kembali apa-apa kecuali membaca model: status (keberhasilan/kegagalan), peristiwa yang dihasilkan (it's tujuan utama dari command handler, btw: untuk menghasilkan acara untuk mengingat perintah), kesalahan-kesalahan. Perintah penangan sangat sering membuang dicentang kecuali, itu adalah contoh dari sinyal output dari perintah pawang.
Selain itu, penulis istilah, Greg Young, mengatakan bahwa perintah selalu sync (jika tidak, itu menjadi event): https://groups.google.com/forum/#!topik/dddcqrs/xhJHVxDx2pM
Greg Muda
sebenarnya saya mengatakan bahwa asynchronous perintah doesn't ada :) yang benar-benar acara lain.
Jawaban untuk @Constantin Galbenu, saya menghadapi batas.
@Misanthrope Dan apa sebenarnya yang anda lakukan dengan peristiwa-peristiwa itu?
@Constantin Galbenu, dalam kebanyakan kasus, saya don't membutuhkan mereka sebagai hasil dari perintah, tentu saja. Dalam beberapa kasus -- saya harus memberitahu klien sebagai respon dari permintaan API.
It's sangat berguna ketika:
Dan saya dapat memberikan contoh untuk kasus kedua. Bayangkan kita membuat Sumbu-seperti layanan, kami telah LikeStranger perintah. Perintah ini DAPAT mengakibatkan StrangersWereMatched jika kita seperti orang yang sudah menyukai kita sebelumnya. Kita perlu untuk memberitahu klien mobile di respon apakah pertandingan itu terjadi atau tidak. Jika anda hanya ingin memeriksa matchQueryService setelah perintah, anda dapat menemukan pertandingan di sana, tetapi tidak ada jaminan bahwa pertandingan itu terjadi sekarang, karena kadang-KADANG Tinder menunjukkan sudah cocok dengan orang asing (mungkin, di daerah berpenghuni, mungkin inkonsistensi, mungkin anda hanya memiliki 2 perangkat, dll.).
Memeriksa respon jika StrangersWereMatched benar-benar terjadi sekarang ini sangat mudah:
$events = $this->commandBus->handle(new LikeStranger(...));
if ($events->contains(StrangersWereMatched::class)) {
return LikeApiResponse::matched();
} else {
return LikeApiResponse::unknown();
}
Ya, anda dapat memperkenalkan perintah id, misalnya, dan membuat Pertandingan baca model untuk menjaga itu:
// ...
$commandId = CommandId::generate();
$events = $this->commandBus->handle(
$commandId,
new LikeStranger($strangerWhoLikesId, $strangerId)
);
$match = $this->matchQueryService->find($strangerWhoLikesId, $strangerId);
if ($match->isResultOfCommand($commandId)) {
return LikeApiResponse::matched();
} else {
return LikeApiResponse::unknown();
}
... tapi berpikir tentang hal ini: mengapa anda berpikir bahwa contoh pertama dengan logika sederhana adalah lebih buruk?
Itu doesn't melanggar CQRS pokoknya, saya hanya membuat implisit eksplisit.
Itu adalah stateless abadi pendekatan. Kurang kesempatan untuk memukul bug (misalnya jika matchQueryService
cache/tertunda [tidak langsung konsisten], anda memiliki masalah).
Ya, ketika kenyataan yang cocok adalah tidak cukup dan anda perlu untuk mendapatkan data respon, anda harus menggunakan layanan query. Tapi tidak ada yang mencegah anda untuk menerima peristiwa-peristiwa dari command handler.