Things You Must Know Before Switching to Microservices

Transitioning to microservices can turn out badly. Here’s what you need to understand about microservices.

Giedrius Kristinaitis
Level Up Coding

--

Microservice network
Photo by Shubham Dhage on Unsplash

You Might Not Need Microservices

Before you switch to microservices you first need to answer the following question: why do you need them? The answer must be informed and honest.

If you answer that you need microservices because they’re scalable, can be independently worked on by separate teams, are robust, small, and all that kind of stuff, then put the idea on hold.

I’m not saying that the mentioned things are not good, what I’m getting at is that you must understand how to achieve them if you want to have a decent microservice architecture.

Think about your situation

What you need to answer yourself is how microservices will help your particular situation. Think about your situation, and don’t blindly copy what big tech companies do, because their domain is most likely different from yours, and they have their own reasons that might not exist for you. You can listen to their general advice, just don’t be like “oh, this company is doing X to solve their Y problem, so we’ll do the same” when you don’t really have a Y problem.

Saying things like “if we use microservices we’ll be able to reduce development costs, we’ll scale better, etc.” is not a good answer, because it’s very generic and does not explain how.

Here’s what a good answer might look like: “we need to process a lot of batches of X data, however, we can’t do it anymore, we can’t scale because each batch is unnecessarily coupled to process Y which can’t be made any faster, nor does it need to, so we need X to be decoupled from Y”.

Such an answer would tell exactly what problem you’re having and why. Identifying your problem is very important. If you can’t identify your problem you’re at a high risk of making your life too complicated by needlessly starting with microservices.

You can start with a monolith and switch to microservices later

I’d like to address a possible concern people may have — the assumption that if you don’t start your project with a microservice architecture you’re doomed to stick with your decision and can’t switch to microservices later; you won’t be able to extract parts of your system into separate services when needed.

The only way for that to be true is if you don’t think about making your system loosely coupled, and if you don’t think about loose coupling, no matter what architecture you choose, it’s probably not gonna work out, microservices included.

So if you think that you must start with microservices from the get-go you’re already implying that your services will be too coupled and too static to actually qualify as microservices. If you can have a loosely coupled monolithic system, you will be able to convert it to microservices.

If you can’t have a loosely coupled monolithic system, microservices will make your life even worse, a lot worse.

This brings me to the next thing you must understand.

Microservice Architecture Is Not a Tech Stack or a Clear Technique, It’s a Design Problem

Here’s a common approach to microservices: you have an idea, you identify what services you’re gonna “need”, you bootstrap repositories for each service, you create teams for each service, you tell everyone that they must use REST for communication between services, you identify places where you’re gonna “need” queues, you work on the idea for some time, you implement all requirements, the system is working, but it’s very slow, and then the management comes in all excited and says:

Hey, we need this fancy new feature to be implemented by next month, we’re sure you can handle it, after all, you told us that the microservices will be easy to develop and will be robust to changes, that would be all, go do whatever it is that you do, we don’t care about that, and we’re not crazy enough to start doing so, because if we did we’d realize that we can’t micromanage you anymore and tell you to sacrifice everything to deliver a feature in an impossible timeframe, and we can’t allow that, because the CEO needs to think we’re delivering value if we want to keep our jobs which are only relevant because you solve problems we create and we take all the credit for it and tell everyone that problems are being solved because of our brilliant management skills, in short, good luck, we trust you, bye.

Then you realize that you can’t implement the fancy new feature and that the whole architecture is a catastrophic failure, but at least no one can fire you for that, because you’re the only one who knows how it works.

You don’t know what services you’ll need

What’s so wrong with such an approach? Every single thing. The biggest one is the assumption about the specific services you’re gonna “need”. The thing is that at the beginning of a project you can’t know for sure how it’s gonna evolve, you can’t know whether whatever you establish at first is good or not. You just can’t, so why stick with the initial assumption about individual services?

When you establish exactly what services you’re gonna “need” and how they’re gonna work and strictly stick with it you’re shooting yourself in the foot, and it leads to an instant legacy codebase that’s a spitting image of a big ball of mud monolith. Except a lot slower, because there are a lot of network calls that could be simple function calls in the same process.

Technologies don’t define microservices

Believing that using specific technologies, having a lot of networking involved, and having everything happening in parallel makes your architecture microservices is very dangerous. You wouldn’t use a 5th-generation stealth fighter jet with precise laser-guided missiles to shoot down a fly. That’s what you end up doing when you believe that technologies and parallel processing make up microservice architecture.

Using REST doesn’t mean you’re doing microservices, using RabbitMQ doesn’t mean you’re doing microservices, having separate code repositories doesn’t mean you’re doing microservices, and having separate teams working on them doesn’t mean you’re doing microservices.

Microservice architecture doesn’t have a process you can follow

The obvious question that follows is what actually makes a microservice architecture. The thing with microservices is that there are no strict conditions that you can check and say that you’re doing microservices. For example, take the most popular architecture — layered architecture, sometimes called n-tier architecture. It states that the system consists of layers, and it even defines some common layers, the guidelines for such architecture are a lot more clear.

When people hear of an idea, or, in this case, an architecture, they look for unique characteristics that identify it, so it would help them understand what it is, but the characteristics of microservices are not obvious, they’re not easy to spot, so people often don’t see them.

There’s no process you can follow that would turn your architecture into proper microservices.

When there’s no process, then the next obvious things about microservices are separate repositories, network calls, concurrency, and separate teams. Then people think that if they’re doing those things they’re doing microservices.

Do you know what else has the same properties? Distributed monoliths (I like to call them distributed plates of spaghetti), that’s the state that a lot of transitions to microservices end up in.

Microservice architecture characteristics

So what are the true characteristics of a microservice architecture?

Loosely coupled services, good abstractions, independent deployment for each service (you could argue that this is the only technical thing about microservices since deployment is a technical thing, but it still doesn’t say anything about tech stacks, so just using Jenkins for deployment doesn’t count as independent deployment), closely related concepts that are together and not separated for no reason, properly encapsulated services.

If you have all these characteristics then you can call your architecture microservices. They make microservices a design problem, and the only way you can achieve them is through good design decisions.

If you can’t make good design decisions in a monolithic codebase, you won’t be able to have microservices.

Ignoring this fact results in terrible things where what could’ve been simple is overcomplicated by accidental complexity introduced by concurrency and tech stacks (accidental complexity is the complexity that results from things that are not your problem domain, for example, a framework).

Transitioning From an Ugly Monolith to Microservices Requires Changes in Engineering Practices

You might be in a situation where you have an old monolithic system and want to replace it. That’s fine if you have your reasons for it (just saying that the old system is bad is not a good reason to start with microservices right off the bat).

The old monolithic system is a huge pile of spaghetti and needs to be rewritten. The biggest mistake you can make in such a situation is not learning from past mistakes. You should sit down and closely inspect what bad (engineering) practices or processes led to the state that it’s in.

If you don’t do that you’re bound to repeat the same mistakes when you rewrite the system. You know what they say, history repeats itself, and the only way to prevent it is to learn about history.

You just can’t rush into a new project with the same engineering practices you used in the old one and expect things to magically turn out different this time around. The old one failed for a lot of reasons, and you can’t ignore them. Everyone working on the new project should be informed about them.

Good architecture is difficult to get right, and the only way to achieve it is through good engineering practices. What are those practices? The answer could be a whole book, so it’s out of the scope of this article. Just keep in mind that it won’t be any different next time if you don’t change anything.

Saying “this time we’ll make it right” and not specifying how never works.

Key Points Summarized

  • If you can’t state exactly how microservices will help you, you might want to reconsider your decision to attempt microservices.
  • You can switch to a microservice architecture later if your system is loosely coupled and has proper abstractions.
  • Prematurely identifying services often leads to an architecture that is too static to be changed in the future, which results in a distributed monolith.
  • Having separate code repositories and using concurrent inter-process communication introduces a lot of complexity and doesn’t turn an architecture into microservices.
  • Having separate teams working on separate parts of the system doesn’t turn an architecture into microservices.
  • Microservice architecture is not a process or structure you can follow, it’s a complex design problem that can only be done right with the help of good engineering practices.
  • If you don’t have good engineering practices, then no matter what architecture you use, it most likely isn’t going to be good.

Conclusion

There are a lot of ways for a microservice architecture to turn into a horrifying nightmare.

Microservices don’t have strict rules you can follow to get them right. That’s why they’re difficult, they’re not a silver bullet you can apply to your project and make it top-notch.

This is what everyone must understand who is either working on microservices or wants to switch to such an architecture unless they consciously want their life to be too complicated.

--

--

I’m a software engineer who loves to explore ways to make development more effective and enjoyable. Love to call out bad practices and misunderstandings.