Goddd Design Decision Finally
As no one knows (because no one gives a fuck), GoDDD is my implementation of Event Sourcing in Golang.
I was really anoyed with this implementation. Normaly, a Domain object called on a mutation method should emit an event that is applied on itself after being saved in an event stream.
For this to work properly :
- The event stream should receive an event that have a specific (known) type (let’s say Event);
- The domain object should be able to received the event name and the event payload to mutate its state;
These two requirements are contradictory because the event payload is of a different structure every time. For the first requirement to be satisfied, we have to abstract these different structures. For the second to be satisfied, we have to known exactly which structure it is.
In a dynamicaly typed language (like Python), it is very easy. The event stream just receives a “something” for the payload and saves it. After that, the event handler method is found on the domain object by its name and is called with the “something” payload. Boom, it is done.
This is not the same story in typed languages (like Golang). Golang WANTS to know the type of the payload in the event stream. So we have to make an abstraction of the payload (say an array of bytes (which implies a first serialization)). Next, we have to call a “generic” event handler method that will, for each event type, contain a call to the appropriate method. The appropriate method will be called with a byte array that needs to be deserialized to get back the real payload. This is slow. This contains a lot of boilerplate code. This is error prone. This is ugly as fuck.
Thinking about this problem today, I was banging my head against the wall while surfing the web when a found a beautiful library that brought a part of solution together with an idea for the rest of it.
The library is msgp (or MessagePack). This is a binary serialization library that generates the mandatory code in order to perform the serialization. Code generation is not a new thing, Protobuf does it very well. However, unlike Protobuf, msgp makes it from the actual definition of the data in the Golang source files. This is beatiful because, data have not to be described twice (once in the code and once in another format). The code is generated and is linked to the objects at compile time(so it is fast and very easy to use).
That resolve the first part of my problem. Slow (de)serialization. The method that sends the event to the event stream can just know that the payload respects a specific interface (msgp.Marshaller
) and is thus able to marshall the payload to a byte array by itself. After that, from the event name and the binary payload, it is possible to find the appropriate payload object and unmarshall the payload into it.
A problem that stay is that, this solution needs a big method that for each event name and byte payload is able to unmarshall the event and call the appropriate event handling method. But this library process gave me an idea on how to tackle this problem. The idea is to generate this method. This generation is easy. For each event type :
- Create a case in a switch that contains :
- The event instantiation
- The unmarshaling from the binary content
- The call to the appropriate method on the domain object (the method name can be generated here)
This solution is beautiful. It is fast (because msgp is fast). It is reliable (because code is generated). I am very happy with it.
I have not yet implemented the code generation tool. It will maybe be way more difficult than I think it will be but who knows ? After a so intense reflexion on this problem, I am happy and a little proud to have found this solution.