I have talked about using Go for Merqio Store NG rewrite but decided to stay with what I know — PHP.
Well, after watching too many videos about microservices, event sourcing, gRPC and other cloud stuff I came o a conclusion that Go is the right tool for the job.
I wanted to branch out of PHP for a while now but did not have a use case. Now I have a great one.
It took me two days to feel comfortable in Go. After almost 18 years of making websites, and I guess of those years using PHP, it is easy to pick up a new language. The concepts are universal, you only have to learn the new syntax.
And let me tell you, whenever I saw Go code, I hated its syntax. But as with anything else, you get used to it and not even notice it anymore.
The reason I have decided to make this move is that I have enough time where I should master the language enough that it does not get in my way. Another reason is that it is very fast compared to PHP. Up to 20 times faster.
It is a compiled language so deployment is that much easier. The size of the container is tiny compared to PHP. There are no dependencies. No need for Nginx or other webserver in front of PHP process. That means overall less resources are needed to run Go code compared to PHP in terms of size, number of containers, CPU, RAM, disk…you name it. Which translates into smaller bill for the cloud services but also performance gain at the same time. Win win.
A great example when it comes to performance is this quote:
NATS was originally built with Ruby and achieved a respectable 150k messages per second. The team rewrote it in Go, and now you can do an absurd 8–11 million messages per second.
..and PHP is faster than Ruby..
Go has built-in concurrency so parallelism is a first-class citizen.
Simply put, for microservices architecture, Go is simply made for it.
So now, that I can actually write Go code, I am still not much further than I was a few days ago. You see, with PHP I have wrote my basic “framework” for event sourcing in three days. And I am totally new to ES as well.
But Go is not OO language, like PHP is. So instead of inheritance you have to do composition and it is very limiting compared to true OOP.
The simplicity of Go has its drawbacks. You don’t have to just learn new syntax and way of doing things. You also have to think differently about the code since Go is a dumbed down language, which is also the reason one can be productive in it in less than a week.
And so at this time I am quite struggling with coming up with some basic ES\CQRS framework so that I don’t have to write all services from scratch every single time.
Go has this thing called struct composition where you can embed one object(struct) into another and call properties and methods on that parent just like you would on the child. So there is a small light of hope ahead that maybe I will be able to write a basic skeleton.
Unfortunately Go does not have anything like method_exists() so you have to use switch inside the handler method and process logic centrally instead of delegating the logic to appropriate methods. For example I have a single applyEvent() method that can delegate the event to onFooEvent() methods based on the event type which makes the code very clean. But I cannot do anything like this in Go. I guess if I would have to sum it up, in Go you have to know exactly what is going on in your code, in advance.
Of course, there are some libraries that do ES\CQRS in Go, especially Event Horizon, but all code I’ve seen so far seems too opinionated and not light weight enough for my taste. Not to mention that none I’ve seen so far maps the events to aggregate type, aggregate id and aggregate version. This is needed for concurrency and correct order of events. If there would be some dominant player on the “market” I would probably use it but even the EH, being the most popular, it has only 435 stars on GitHub which is really not that much and I want something solid that I know will be good a year or two from now. I really do not want to do any massive rewrites in the future only because I have chosen the wrong underlying framework.
Beside that I am new to designing microarchitecture, event sourcing and domain driven design so I’m moving very slow right now. Just trying to figure things out, watching a ton of videos on YouTube and reading articles.
As any coder, I would really love to get my hands on some code but due to this I simply have to get the theory right.
Currently, my idea about approaching the code for the micro service is to create the aggregate the service is responsible for(like Client, Product,…), define commands that can be executed on that aggregate or in that domain, and events that can be emitted.
Then I need to store those events somewhere so I need a driver for the DynamoDB so I can create and load the actual aggregates.
Next step is to communicate with outside world, so I will have to create an API. This is where gRPC comes in. I though about how to approach this and I think that having gRPC for inter-service communication is the best solution.
gRPC can generate fully working clients and server stubs from .proto specs so that makes my job much simpler and I don’t have to write a client code any more for different languages.
gRPC is of course not that wildly supported so REST will be needed too in order for services to be able to communicate with outside world. Luckily there is gRPC REST Gateway which can relay gRPC commnication via REST and it also means I can generate OpenAPI specs.
So hopefully, this will take care of a large chunk of the microservice.
I will also have to create a central repository with all gRPC proto specs so if there is a change made, any service can pick up on it or a new client can be re-generated automatically. The same goes for events and commands. Each service listening for events has to be able to process all versions of the event so each event has to have a public schema available that can be accessed by other services so they can upcast the event according to correct schema version.
In PHP I’ve used JSON Schema but in Go I am not sure which technology I’ll should pick at this time.
Hopefully I will have my first service up and running by the end of this week. As I’ve said, I would like to get my hands on some code already :)
PS: I am not leaving PHP for good. On the contrary. I love and appreciate it even more :)
PPS: I am giving up on trying to write some basic ES framework. Currently I do not see how this can be done properly in Go without coming up with some weird workarounds. So all services will be totally custom, unfortunately.