Microservices. Are they outdated?

I've seen some articles claiming that Microservices are dead. Most point to new strategies and approaches which solve some of the same problems, and others speak the benefits of monolithic architectures (yes, some exist). But, ultimately, I do not think that Microservices are dead. Or at least not conceptually.

I'll start by claiming that most supposed microservices aren't true microservices to begin with. So, I'll propose that when referring to microservices, we're talking about anything which could be "generally accepted" as being a microservice and not just things which tick every single box.

But, I guess we need a baseline. For the purposes of this article, I'll call a microservice an application which meets the following criteria:

  • Is a part of a larger eco-system of applications which by modern standards would still have been considered sensible as a monolith (IE - if you have a CRM and an ERP, these are totally different things and wouldn't naturally live in the same application to begin with, so "splitting" them into separate apps is NOT making microservices). But, taking your ERP and splitting out different types of activities into separate services, even if they could still have been broken out further would be.
  • Each microservice owns (conceptually at the least) a unique set of the data model. This means that even if multiple services share a DB in production, that it would either be "incidental" or something which could be easily changed. In short, if service A made a change to something service B relied upon, service be unaware that the change happened unless the changes were exposed via a shared proxy client/contract/etc...
As you can see, I'm not too picky on what I will let pass as a Microservice. From my experience, simply breaking up an existing application (or writing a new one) as multiple services with a concern for data ownership is enough to at least "prep" the architecture for further compartmentalization later. And that to me is the key to ensuring that you can rework your services as needed.

With that out of the way, the reason I don't think that Microservices are an outdated concept is simple; I believe that those who believe they are outdated are either experienced in domains where they may not have been applicable, or they haven't scaled yet to a point where their nonsense starts breaking down.

In this regard, I will put Google and Microsoft as the authority on the matter. Both have their own cloud native service offerings, as well as their own programming languages and frameworks, and both advocate AND use microservices themselves. I do NOT consider any company to be logically infallible. But, I not only agree with their stance, I also believe that they have the talent, the funding and equally importantly, the motive to find the right answer. 

But, that is not answer. I'll call that the "endorsement" of what I'm about to say next. 

While there may be some domains where Microservices do not make sense. I think it is FAR more limited than one might think. Most people will say that it introduces overhead and complexity. And that is correct. Or at least, it is from a certain viewpoint.

Let's start with performance. If you take one big service and split it into 2 and those 2 services need to talk to each other, there is now network overhead among other things. So, is it slower for the 2 services to talk to each other than simply exist together? The logical answer is yes. But, it is also the wrong answer. 

Hear me out. YES, in the BEST case scenario the microservices are slower. But, at that scale both should still be able to EASILY perform well within acceptable ranges. As load scales though, the monolith can only scale by duplicating the entire application domain over and over again. And, it cannot shift bottlenecked processes to different physical hardware or scale only the pieces which are stressed. Typically, performance of a monolithic piece of software will degrade under load more readily than a microservices approach. 

In short, no mainstream solution will produce unacceptable performance unless your underlying infrastructure or code is severely flawed. As such, you should concern yourself more with what happens to performance at scale. My experience has been that companies are only proactive about performance at the start of a project and are almost just reactive once live. But, that is when it becomes the hardest to adapt. So, it makes sense to change how measure performance to focus on long term impacts. 

I'm not going to say that there are no possible solutions to monolithic scaling problems. But, those typically come with their own overhead and they increase the complexity of the application. Which leads right into the next point; complexity.

Is a microservices application more complex than a monolith? Again, the answer is no.

And again, hear me out. YES, initially the monolith will be less complex. But, as the project scales and starts bumping into performance issues... well, fixing those problems in a monolith is much more complicated than the complexities added by simply going with microservices to begin with. And converting to a microservices architecture later is typically harder once you get started. And most projects I've heard about have ended up going the rewrite route anyway.

I also do not believe that the complexity is actually greater even in the short run once the application grows above a certain size. And there is a simple reason for that; forced architecture decisions. Microservices, almost by design, force you to decouple your code. By having so much logic external to each other they are better suited from the get go for dependency injection and for writing unit tests. But, also, this decoupling tends to wind up meaning cleaner code which makes it easier to iterate on and maintain. And that is actually a decrease in complexity.

On a small enough project, the benefits may never outweigh the costs. But, on a small enough project you may also be in the small group where Microservices simply don't make sense.

But, there are other benefits to microservices. One problem I frequently hit is that a lot of my data is best served by a document DB. But, not everything. There are other things which are better stored in a relational database or even in a simple key-value storage system like Redis. It is a nightmare to try and have multiple persistence models in the same service. But, these concerns also tend to spread themselves out across lines where separate microservices would make sense.

A simple example is an application I write for my brother. It manages his wheel & tire business. Orders are best stored in a Document DB. But, there are data elements which are best stored in a relational database like the Customers and their Vehicles. This data may get flattened out into the Orders, but that is actually a good thing so long as their is an immutable key to look up the current version of those objects. And then there are things like settings which should maybe just be loaded into memory at startup and flushed to disk as they are changed. If each of these were managed by different microservices disparate ways in which they manage data would be easier to manage.

And while I'm choosing data persistence here, the same is true of so many other design decisions. Typically, monolith teams are forced to decide on the lowest common denominator. In the real world, different databases serve different purposes with differing levels of success. Different languages and frameworks also have their own performance considerations which may impact things. Design patterns have trade offs as well. Caching. Authentication. Authorization. Every part of an application has different concerns. Monolithic architecture often has to compromise on the standards it imposes.

I just wrapped up a project that I felt was going to be the most inane example of Microservices ever. I knew it was a stepping stone. But, now that I'm approaching completion, I know it was right, even for this INCREDIBLY silly example.

I have that project I wrote for my brother. I also had a few other Windows apps I wanted to turn into web applications like my brother's application. But, I didn't want to write authentication over and over again. So I said... what if I finally started my "universal API gateway project" and incorporated microservice UIs into it with the login page being the first Microservice UI?

See, that sounds silly right? My first microservice UI is literally JUST. A. LOGIN. PAGE. But, conceptually, it is so much more. Stripping the login page from my existing SPA has a lot of implications.

The API Gateway is an in-memory configured YARP reverse proxy. Some cluster endpoints are flagged as authenticated and some are not. The Gateway, via a module system, manages authentication. If a call is authenticated and matches a set of routes, it is then load-balanced to either the authenticated or unauthenticated endpoint(s).

This service is actually pretty small. Especially because of the modular approach. The Login UI is also, unsurprisingly small. But, the cool part is that the user/client is COMPLETELY unaware that once authenticated they are hitting a completely different service. This means I can, if necessary, share state in the browser in a secure fashion between pages if I needed to simply using the local storage. I can also share cookies safely in such a fashion. And, I can talk to multiple services on the back end without CORS concerns. Everything is routed through the same host; my API Gateway.

The login UI is an Angular application and the main application is Vue.js. Currently, the authentication is stripped directly from my old code and data is stored in SQL. But, when I start adding new applications I'm going to build a dedicated authentication service. I'm going to use Mongo because I want it to support multiple authentication models. So the actual stored data can change from record to record. 

And, I could then, at will, switch my brother's app between whichever auth provider I wanted. 

I also plan to change from a session stored in a table to a JWT token. And again, when I build that session persistence model, I'll be free to switch it into any application that I want which is using my API Gateway.

I probably won't go too crazy on microservice UIs. I don't want to over complicate the routing rules. And the same will likely be true of my services. I will likely end up with dedicated microservices for Authentication, Authorization, Configuration and Localization. Session management will likely just need a module with no service. And then each of my applications, as they are quite small, will likely be just 1-3 microservices + 1 UI + login screen. 

Authentication and Authorization will be handled within the Gateway and the Clients and Microservices will be able to request details for the current user if they care/need them. That means that I don't need to duplicate that Auth work in every service, nor do I need to do so in every application.

I also end up with a shareable set of services which makes future applications and microservices much easier to get off the ground. It also means my smaller individual services are quicker and easier to rewrite.

This being the third revision of my brothers software with the prior two being monoliths, I can say, I very much look forward to finishing this last little bit.

Comments

Popular Posts