Microservices is a huge topic. However, it’s not a very precise topic.
Martin Fowler agrees:
While there is no precise definition of this architectural style...
Diving into the topic of microservices, you’ll quickly discover that there are many differing opinions.
For example, Martin Fowler suggests that you shouldn’t start a new system using a microservices architecture.
However, his peer Stefan Tilkov suggests that you should always start with a microservices architecture. 🤔
Udi Dahan has believed that microservices, as defined, are still too fine-grained and potentially lack critical concerns around real boundaries and UI considerations.
Who should we believe?
Let’s face it: opinions in tech are always changing and are often not as black-and-white as we’d like.
“Best practices” are often shifting every few years.
Once we thought DRY was the best thing since sliced bread. Now we are told that sharing code can be one of the most damaging architectural decisions one could make.
What about microservices?
Most coverage about microservices is shallow, vague and contradictory.
Sadly, however, there’s not much information that outlines what the microservice style is and how to do it.
To highlight this fact (it’s a very important fact), let’s look at InfoQ’s Architecture And Design Trends Report for 2019.
Notice that microservices is in the “late majority” section. This means microservices are fairly common in the industry.
Now, look at the 2nd section labelled “Early Adopters.” See that one called Correctly built distributed systems?
As an industry, in general, we’ve been doing microservices, but not well.
However, let’s look at whether you should use a microservices architecture as a general concept.
We’ll begin by asking some fundamental questions about microservices:
- What is a microservice?
- What is a microservices architecture?
- How many microservices should be in my architecture?
- How big should they be?
- Should my entire architecture be comprised of microservices in order to have a microservices architecture?
- What about macro-services? Is there such a thing?
- If there is, are they better or worse than microservices? Why?
- What about my UI? Should that still be one massive single-page application?
- Can I use an MVC based web framework and still be using microservices?
- How autonomous should they be?
- How does this all relate to the cloud?
- Is serverless a kind of microservice architecture?
- If I do have a server can I still have a microservices architecture?
These might seem like simple questions. But once you dig a little further you’ll find that the answers are not so straightforward.
Martin Fowler recognizes that microservices don’t have a precise definition. However, he tries to clarify what a microservice might look like:
...services are independently deployable and scalable, each service also provides a firm module boundary, even allowing for different services to be written in different programming languages. They can also be managed by different teams.
Given this definition, the typical microservices architecture you’ll see will look like this:
Each microservice can be deployed and scaled on its own. They are running as independent processes and communicate over the network. Each has its own database.
Ok. Now, take this example:
This is a common architecture you’ll find in real companies who’ve been making money for a while.
Imagine that each of these monolithic applications handles separate areas like shipping, billing, etc.
The glaring problem here is that the shared database can lead to all kinds of issues that are typically avoided via proper encapsulation.
What some companies have done is not re-architect their system to a collection of microservices, but applied proper encapsulation to their monoliths (via bounded contexts from domain-driven design).
I have a question that exposes the general notion of what microservices are supposed to be:
What’s the difference between the microservices diagram and the properly encapsulated monoliths diagram?
The only difference is that the microservices architecture diagram is sharing the user interface across the entire system.
What I find strange is that in most articles and discussions about microservices the issue of UI is hardly ever mentioned.
Given the typical definition and explanation of microservices, the difference between the encapsulated monolith and “microservice” is not immediately evident.
(What if we removed the UI from some of our monoliths, added a REST API to each and gave them all a shared UI? That sounds awfully similar to the typical microservices architecture diagram you’ll see…)
After all, the biggest reason for moving to microservices is to enable different cross-functional teams to fully own their own products.
This works very well given the properly bounded monolithic approach:
But, the general “microservices architecture” falls short on this:
Who owns the UI? Everyone? No one? Create a new team?
The reality is that software systems are much more fluid and dynamic than we would like to think.
It’s harder than we’d like it to be.
Software architecture involves taking many smaller ideas and putting them all together in a way that makes sense for your use case.
Imagine a business that has an existing legacy system.
This monolithic system is generally pretty risky to change. The business demands a faster time-to-market for some new features.
Should we rewrite the entire system as a collection of microservices?
It would make more sense to add new functionality via focused and encapsulated services that own dedicated business functions.
This would be more of an evolutionary approach to software architecture (keep reading).
Again, it’s just not so cut-and-dry. We have to think about our existing systems, where we want the business to be in the near future and apply techniques and approaches that allow our business to keep growing and making money.
A poor team will always create a poor system – it’s very hard to tell if microservices reduce the mess in this case or make it worse.
And don’t forget that most of us aren’t even building distributed systems correctly anyways:
Awareness of the “microservices” architectural style may be moving into the late majority, but the related themes of “correctly designing distributed systems”, and designing for reactivity and fault tolerance are not so far along the adoption curve.
This fluid and more adaptive approach to software architecture is sometimes called evolutionary architecture. This is, in my opinion, just a plain responsible approach to software architecture.
InfoQ has this approach listed in the “early adopters” phase. This indicates that most companies are still just “hammering away” with microservices.
Evolutionary architecture is a broad principle that architecture is constantly changing. While related to Microservices, it’s not Microservices by another name. You could evolve towards or away from Microservices for example.
Since 2011, evolutionary architecture has been in the “adopt” category of ThoughtWorks’ technology radar.
It’s not really that new.
In contrast to traditional up-front, heavy-weight enterprise architectural designs, we recommend adopting evolutionary architecture. It provides the benefits of enterprise architecture without the problems caused by trying to accurately predict the future… We advocate delaying decisions to the latest responsible moment, which might in fact be up-front for some decisions.
That sounds like doing responsible, reasonable and intelligent software architecture to me 😅.
If this interests you, I’d recommend watching this 16-minute discussion by Randy Shoup.
Step zero is to take a real customer problem, something with real customer benefit, maybe a reimplementation of something you have or ideally some new piece of functionality that was hard to do in the monolith.
Do that in the new way, first, and what you are trying to do there is to learn from mistakes you inevitably will make going through that first transition, right? You do it in a relatively safe way, but at the same time you do with real benefit at the end.
As Randy later points out, it’s perfectly fine to leave certain parts of a system untouched if they have no real reason to change.
There were still pages on this site that were on V2 architecture, simply because they continue to work, they got 100,000 hits a day, no big deal, and they were neither painful enough to migrate nor having the sufficient ROI to migrate. So, they just stayed and they happily stayed.
You might be wondering about the shared UI that appears in most microservices architecture diagrams.
Is there a way to fix that?
Yes, there is. But it’s not so simple as we’d like.
It boils down to allowing each microservice to own it’s UI components.
This allows individual teams to own the entire stack.
What happens when we have a UI that needs to display data from multiple services?
The solution is to compose multiple UI components owned by those services.
In many cases, composite UIs are much more complicated than the image above. But this is a starting point to help you understand where this approach leads.
This isn’t what most people think of when they say “microservices.” Microservices usually don’t have the notion of having UI components that are owned by it.
In discussing this issue, Udi Dahan uses an example of a product’s price. Udi points out the fact that specific services need to own their UI. Otherwise, we break encapsulation.
In this manner, no code outside the service boundary would know about the concept of the product price and thus could not end up coupled to it.
...I don’t really see how a [microservice] could end up having this level of ownership of data.
You’ll hear that microservices need to be around 1000 lines of code or less. At least, I’ve heard that one before.
However, microservices need to own the data, behaviour and UI of a given business context.
We, as developers or architects, shouldn’t get to magically decide how big our services should be. It’s 100% totally dependent on the business context we are modelling.
In relation to the issues surrounding UI ownership, Udi Dahan points out:
You’ll tend to see services that aren’t all that small, and probably not so many of them.
Udi is considered one of the most highly respected experts in building distributed systems. And he’s told us – years ago – that we’re doing it wrong.
Microservices are potentially too micro because they aren’t respecting the boundaries of real business contexts. Instead of focusing on size we ought to focus on proper boundaries (which is a topic for another day).
Should you use a microservices architecture?
You should do what makes sense for your business.
For example, your business might want to build new products that require a quick time-to-market.
You could add those new products as entirely separate monoliths that communicate with each other via event messaging to keep them loosely coupled.
They could be built as microservices that integrate back into the existing system via HTTP REST calls or event messaging?
Perhaps there’s an existing off-the-shelf solution that exists which your company can purchase? You could build a custom API on top that will allow integration with the existing system.
There are cases that call for splitting an existing system up into isolated components. They could be microservices.
Or, you could use a plug-in component-like system within a monolithic system.
(I’ve written about an approach to building modular monoliths using .NET Core.)
We haven’t even talked about factors around team skill/competency, project management styles, organizational influences, etc. These are all factors that affect your software architecture!
But, are there guidelines for smaller organizations? Absolutely. And again: the meta-point with all these things is “only solve problems that you actually have”.
I help Saas businesses improve their overall agility and time-to-market of new products and features.
I also offer guidance for teams using .NET Core who need help with building web APIs, framework migrations, improving development processes, etc.
Also, check out my book about keeping your code healthy!
Don't forget to connect with me on: