We engineers have an affliction. It’s called “wanting to use the latest tech because it sounds cool, even though it’s technically more difficult.” Got that from the doctor’s office, it’s 100% legit. The diagnosis was written on my prescription for an over-the-counter monolith handbook. From 2004. Seriously though, we do this all the time. Every time something cool happens, we flock to it like moths to a campfire. And more often than not, we get burned.
I thought I was immune to this. I thought I knew better. So I thought that when I became interested in microservices, I was being rational. Narrow deployments. Redundant duplicate instances of each service. Kubernetes. What’s not to like? Sounds great in the planning stage. But then you get to the implementation.
Building microservices is generally harder than building a monolith. It’s that simple. And as a team, you have to decide how to handle that hardship. If you’re not careful, it can cause all sorts of problems. Like scope creep, because the implementation is too complicated. Or declining morale, if your team isn’t experienced with building a distributed architecture and hits too many roadblocks. All these things and more hit my team like a freight train.
It was our first medium-scale project. Started out well enough, until we got to cross-service transactions. As someone who has been through this challenge several times, all I can say is becoming a US citizen is probably easier. We were using the saga design pattern described by microservice evangelists like Chris Richardson. Won’t get into it here, but it’s essentially a way you represent a task that involves multiple separated services. Sounds pretty in theory. Until you actually build it.
It’s not that the code is disgusting. It’s just different than building a monolith. Specifically, it’s much trickier to debug. First of all, you need to configure the correct state for multiple different services before testing anything you write. That itself takes a while. Usually, you just run the new function with a console log on every other line. But not with microservices. There’s a whole setup process involved with testing anything, even the smallest helper function. It’s not just different, it also takes a while even after you get used to it.
Don’t get me wrong, there are plenty of perks, too. I especially appreciate the redundancy — it has saved us on a couple of occasions. Plus, the separated services help with deployments. We’re building trading bots, after all. There are tweaks, fixes, and modifications to be made all the time. Frequent deployments are much easier when you can deploy one service without disturbing all the others. To be fair, I’ve seen some examples of this working in monolith-land, too. But it’s not as straightforward, as far as I understood. My point is, the advantages are clear and worth the cost. But I still think we shouldn’t have done it.
We simply didn’t need it that badly. What we needed more was the time we lost building our own message broker implementation using Redis streams. Moral of the story: If you have to ask whether you should use microservices, you probably shouldn’t. To do it well requires skill, time, and careful design. Make sure the benefit is worth those sacrifices. Besides, don’t sweat it if you’re using boring old tech. At the end of the day, it’s more important to have working, boring code rather than half-baked, trendy code.