Saya menemukan desain Event Sourcing dan saya ingin menggunakan dalam aplikasi di mana klien REST diperlukan (RESTful to be exact). Namun saya gagal menghubungkan ini bersama-sama karena REST cukup mirip CRUD dan sumber acara berbasis tugas. Saya bertanya-tanya bagaimana Anda bisa merancang pembuatan perintah berdasarkan permintaan ke server REST. Pertimbangkan contoh ini:
Dengan REST Anda dapat menempatkan negara baru ke sumber daya yang disebut File. Dalam satu permintaan Anda dapat mengirim nama file baru, Anda dapat mengubah folder induk dan / atau mengubah pemilik file dan sebagainya.
Bagaimana membangun server sehingga saya bisa menggunakan sumber acara. Saya sedang memikirkan kemungkinan-kemungkinan ini:
Tentukan pada server yang bidang diubah dan membuat perintah yang sesuai (
RenameFileCommand
,MoveFileCommand
,ChangeOwnerCommand
, ...) dan pengiriman ini secara individual. Namun dalam pengaturan ini, masing-masing perintah dapat gagal membiarkan orang lain keluar dari transaksi dan dengan demikian keluar dari "atom" perubahan ke sumber daya.Dispatch hanya satu perintah (
UpdateFileCommand
) dan dalam penangan perintah, lebih tepatnya di agregat, menentukan bidang yang berubah dan mengirim peristiwa individu, bukan (FileRenamedEvent
,FileMovedEvent
,OwnerChangedEvent
, ...)Yang ini saya tidak suka sama sekali: Dalam permintaan ke server saya akan menentukan dalam header yang perintah untuk digunakan, karena UI masih berbasis tugas (tetapi komunikasi dilakukan melalui REST). Namun itu akan gagal dalam penggunaan komunikasi REST lainnya (misalnya dalam aplikasi eksternal) karena mereka tidak terikat untuk mengubah hanya satu bidang dalam satu permintaan. Saya juga membawa kopling yang cukup besar ke backend berbasis UI, REST, dan ES.
Yang mana yang Anda inginkan atau ada cara yang lebih baik untuk menangani ini?
Catatan: aplikasi ditulis dalam Java dan Axon Framework untuk event-sourcing.
sumber
Jawaban:
Saya pikir Anda mungkin memiliki proses pengguna untuk implementasi ketidakcocokan di sini.
Pertama: apakah pengguna secara jujur ingin melakukan beberapa perubahan pada file secara bersamaan? Mengubah nama (yang mungkin atau mungkin tidak termasuk perubahan jalur?), Perubahan kepemilikan, dan mungkin perubahan konten file (demi argumen) tampak seperti tindakan terpisah.
Mari kita bahas jawabannya "ya" - pengguna Anda benar-benar ingin melakukan perubahan ini secara bersamaan.
Dalam hal ini, saya akan sangat menyarankan terhadap setiap implementasi yang mengirimkan beberapa peristiwa -
RenameFileCommand
,MoveFileCommand
,ChangeOwnerCommand
- untuk mewakili ini tunggal maksud pengguna.Mengapa? Karena kejadian bisa gagal. Mungkin ini sangat jarang, tetapi pengguna Anda mengirimkan operasi yang terlihat seperti atom - jika salah satu dari peristiwa hilir gagal, maka status aplikasi Anda sekarang tidak valid.
Anda juga mengundang bahaya ras pada sumber daya yang jelas dibagi antara masing-masing penangan acara. Anda perlu menulis "ChangeOwnerCommand" sedemikian rupa sehingga nama file dan path file tidak menjadi masalah, karena mereka mungkin ketinggalan zaman pada saat perintah diterima.
Saat menerapkan sistem diam non-event yang digerakkan dengan memindahkan dan mengganti nama file, saya lebih suka memastikan konsistensi dengan menggunakan sesuatu seperti sistem eTag - memastikan bahwa versi sumber daya yang sedang diedit adalah versi yang terakhir diambil pengguna, dan gagal jika itu telah dimodifikasi sejak saat itu. Tetapi jika Anda mengirim banyak perintah untuk operasi satu pengguna ini, Anda perlu menambah versi sumber daya Anda setelah setiap perintah - jadi Anda tidak memiliki cara untuk mengetahui bahwa sumber daya yang diedit pengguna benar-benar adalah versi yang sama dengan sumber daya yang terakhir mereka baca .
Yang saya maksud dengan itu adalah - bagaimana jika orang lain melakukan operasi lain pada file pada waktu yang hampir bersamaan. 6 perintah bisa menumpuk dalam urutan apa pun. Jika kita hanya memiliki 2 perintah atom, perintah sebelumnya bisa berhasil dan perintah selanjutnya bisa gagal "sumber daya telah dimodifikasi sejak terakhir diambil". Tetapi tidak ada perlindungan terhadap ini ketika perintah tidak atom, sehingga konsistensi sistem dilanggar.
Menariknya ada gerakan menuju sesuatu seperti arsitektur berbasis acara di REST, yang disebut "Istirahat tanpa PUT", yang direkomendasikan dalam radar teknologi Thoughtworks, Jan 2015 . Ada blog yang jauh lebih lama tentang Istirahat tanpa PUT di sini .
Intinya, idenya adalah POST, PUT, DELETE, dan GET baik-baik saja untuk aplikasi kecil, tetapi ketika Anda harus mulai dengan asumsi bagaimana menempatkan dan memposting dan menghapus mungkin ditafsirkan di ujung lain, Anda memperkenalkan kopling. (mis. "Ketika saya MENGHAPUS sumber daya yang terkait dengan rekening bank saya, akun itu harus ditutup") Dan solusi yang diusulkan adalah memperlakukan REST dengan cara yang lebih bersumber dari Peristiwa. yaitu Mari POST niat pengguna sebagai sumber daya peristiwa tunggal.
Kasus lainnya lebih sederhana. Jika pengguna Anda tidak ingin melakukan semua operasi secara bersamaan, jangan biarkan mereka. POST acara untuk setiap maksud pengguna. Sekarang Anda dapat menggunakan versi etag pada sumber daya Anda.
Adapun aplikasi lain yang menggunakan API sangat berbeda untuk sumber daya Anda. Baunya seperti masalah. Bisakah Anda membuat fasad API lama di atas API RESTful dan mengarahkannya ke fasad? yaitu mengekspos layanan yang melakukan beberapa pembaruan ke file secara berurutan melalui server REST?
Jika Anda tidak membangun antarmuka RESTful di atas solusi lama, atau membangun fasad antarmuka lama di atas solusi REST, dan berupaya mempertahankan kedua API yang mengarah pada sumber data bersama, Anda akan mengalami sakit kepala besar.
sumber
Baru saja saya berlari ke artikel berikut, yang mendorong menentukan nama perintah dalam permintaan ke server di header Tipe-Konten (sambil mengikuti 5 tingkat jenis media).
Dalam artikel tersebut, mereka menyebutkan gaya RPC buruk untuk REST dan menyarankan untuk memperluas Tipe Konten untuk menentukan nama perintah:
Artikelnya ada di sini: http://www.infoq.com/articles/rest-api-on-cqrs
Anda dapat membaca lebih lanjut tentang 5 level jenis media di sini: http://byterot.blogspot.co.uk/2012/12/5-levels-of-media-type-rest-csds.html
Meskipun mereka mengekspos peristiwa domain ke REST API, yang saya anggap praktik buruk, saya suka solusinya karena tidak membuat "protokol" baru hanya untuk CQRS, baik itu mengirim nama perintah di tubuh atau di ekstra sundulan, dan tetap setia pada prinsip RESTful.
sumber