To better understand the concepts of CQRS, event sourcing, and asynchronous service communication, I've been building a small system using Go, MongoDB, and RabbitMQ. This includes the following:
(I envision a similar set of applications being repeated for each microservice in the system, all communicating asynchronously via RabbitMQ)
I feel I have a decent grasp of these concepts at a high level, however in building this system I've run into some trouble with the details. I've found that I need to either:
Use BSON as the RabbitMQ payload to make things "simple" for the Event Publisher - this feels like MongoDB is leaking into the rest of the design, since I wouldn't have chosen BSON otherwise
Make the Event Publisher aware of all event types so it can properly translate a stored event from BSON to JSON (e.g. rewriting dates and UUIDs as strings) for publishing to the message bus - this seems to smell, as the various event types would need to be defined in no fewer than three separate places (command side, query side, and event publisher).
Is this type of problem a normal occurrence for a design using CQRS + Event Sourcing + Message Bus, or is my approach fundamentally flawed?
If this is par for the course, which of the above two options would be better to use in a production setting?
My searches have not turned up anything about this issue, but if you know of an article or blog post that addresses it that would probably be plenty.
There is the concept of event upgraders. The purpose of event upgraders is to transform events coming from the event store as a non-typed data structure into a typed data structure before publishing them (also before aggregates hydration). Those are often used in versioning. Remember more the system grows more are the chances your event types changes so you won't be able to just deserialize from json/bson.
Once you're events are typed correctly serialize them in json to pass them into the bus and deserialize them back on the other side.
event types would need to be defined in no fewer than three separate places (command side, query side, and event publisher)
Just define your event types in a shared library.
Also, it's not related but you really don't need a bus. They cause more problems when it comes to rebuilding projections since they don't keep track of the last read event. Greg Young talked about it somewhere on YouTube (should not be hard to find).