Future / Fog
The latest in software application development is the rise of microservices, wherein applications are offered as a bundle of loosely coupled services. First coined in 2011, this term is now doing the rounds of popular technology circles. According to a survey by Nginx, 36% of enterprises are currently using microservices. Another 26% are in the research phase as far as this new #technology is concerned.
As is common with the advent of new technology, there currently exists a lot of hype around the concept of microservices. Hype does not necessarily equate with superiority, and blindly following the hype can easily result in us making all of the same old mistakes in completely new and different ways.
In order to be more effective at software development, we need to take a step back and unravel the hype from reality.
What does “micro” mean?
You may have heard that a microservice is roughly 100 lines of code. Clearly that doesn’t square with something being created by an entire team of developers using different technologies. (Maybe we should just call it a “service” instead.) A microservice is also clearly not a unit of deployment, or a process in their own right, because they span multiple systems.
These services need not even be deployed separately from each other. Consider a mobile app. We clearly can’t separately deploy a half dozen microservice processes on a mobile device and have them all talking to each other. Such a thing isn’t allowed.
In that case the mobile app, by definition a single physical process, hosts components from multiple microservices all together. Even in a more classic server-hosted software, this same principle applies. You can have a different physical deployment architecture than your logical architecture. Microservices do not need to be deployed separately just because they are logically separate.
A CPU-intensive component may require offloading work to a separate server. This is a separate process boundary, but that does not mean it must be a separate microservice. From a logical perspective, the coupling of the offloaded process does not change.
A microservice is not what everyone says it is. Stop worrying about the lines of code or the physical process boundaries and focus on getting the right amount of code with the right level of cohesion, with appropriate decoupling at a conceptual level. That’s a microservice.
Organizations are divided between whether they should adopt a microservices approach or not.
Here we talk about the prime advantages that it poses, so it can help you decide if microservices is the right thing for you.
Microservices enables companies to adopt a high degree of modularity in its software offerings. Because of this, the application protocols are lightweight—easier to develop, test, deploy, change, and maintain.
Better resilience: Because the entire application components are decentralized into separate entities, a failure in the code of one component seldom spirals over to another component. This is a welcome change from traditional software architectures, where fixing a malfunctioning code would require skimming through the entire code, trying to figure out the linkages. A microservice approach thus creates better resilience, providing a better user experience.
Better scalability: Each service being a separate component, a single service can be scaled up easily without impacting the other application components. This is a key advantage in an age where growth can happen anytime and to any order. To make all mission critical modules scalable, they can be deployed on multiple servers at once.
Tool flexibility: With a microservices approach, you can use specific tools for specific tasks, whichever works best, because the modules are essentially separate and independent. You are, therefore, not stuck with the problem of depending on a single vendor, as is the case with traditional architectures. While each service can utilize its own language or code, it can “talk” to the others effectively. This provides a high level of flexibility in development.
Better Time to market: As a host of loosely coupled services, it is very easy to modify or add new features; the entire code need not be revamped to make this happen. The developer can make changes to one specific service, resulting in smaller development cycles, and better time to market.
There are a few broad classes of problems that microservices (in fact, any technology choice) cannot solve for you:
Incorrect requirements –
Clearly if we start with requirements that are wrong, it won’t matter how fast we can develop, deploy, or scale a system. This goes much deeper than you might think. How often do developers rush off to build exactly what the business stakeholders ask for, only to find out (much) later that it’s not what they actually need? Business stakeholders tend to present us with “solutions” masquerading as requirements. You don’t want the business stakeholders designing your system for you. That’s not their job.
Weak processes –
If you have almost non-existent unit testing, very little integration/acceptance testing, and ultimately the criteria for shipping software is “It works on my machine” then microservices certainly can’t save you.
Bad habits –
Clearly you, reading this technical article, do not have any bad coding habits, but we probably can’t say the same for every last member of our team. Microservices is not going to magically prevent them from writing crappy code.
And while the pain we feel on our projects may seem centered around deployment, the root cause may be more insidious, going back to bad requirements or poor habits. Microservices may help with deployment, but it is just as likely that they will uncover and potentially magnify bigger issues in our processes.
No tool or technology can save us from these problems. Rewriting all your code in Haskell or deploying NoSQL databases will not fix these issues. No other tool, technology, or architecture can fix this kind of stuff. This ultimately boils down to discipline and maturity around software development. It takes time to gradually level up all of the members of the team to work through all of the communication snafus within the team itself and between one development team and another.
There will be benefits from microservices, but the impact of those benefits will always be undermined by weak foundations.
The principles of object-oriented design call for building components that are loosely coupled but high in cohesion. Why do we spend so much time trying to reduce the former at the expense of the latter?
Sometimes we have components that, like the nucleus of an atom, really want to be together. It takes a massive amount of energy to split the atom, and once you do, you get a massive amount of destruction. We focus so much on loosely coupling everything from everything else that, in the end, we end up splitting the atom and making an awful mess.
If we take another look at our layered architecture, we might see that while there is tight coupling/high cohesion top to bottom, sometimes we can identify an element of loose coupling across vertical slices. The things that deal with one set of data don’t particularly care about other sets of data.
For example, if we’re talking about the retail domain, code that deals with products’ names and IDs and descriptions and images is really not that coupled to the pricing of a product and the discounting rules around it. It’s very superficial to only look at nouns when we model our data, saying that a product is a product is a product.
Don’t just assume that since the product is a “thing”, it should be loosely coupled from other “things”. Instead, look at it the other way around. Look at what things really want to be coupled to each other (usually these will be vertical slices spanning all layers) and then allow yourself to start to see boundaries that potentially slice apart your entities. Break these apart into loosely coupled, highly cohesive microservices, each potentially containing a regularly coupled classical layered architecture.
Imagine if a web page, instead of being one large software artifact, was a collection of widgets that happened to be laid out beside each other for a given URL. You would probably have a separate widget for a book’s title and its image, another for the customer rating, and yet others for price, inventory, etc.
The UI itself becomes componentized, where each “micro-view” talks to a “micro-backend” which uses some “micro-database” – all of which become part of a meaningful microservice.
This results in a kind of Lego block type model, so once you have a product price widget, you can now take that micro-view and compose that into many other pages. A shopping cart will use the product details widget, the customer rating widget, the price widget, and inventory widget. These Legos get arranged on page after page to compose full views.
Instead of redesigning a user interface for every single page that we need to do, we can take this collection of Lego blocks and put them together in slightly different ways to fill expanding new business needs.
The long haul
It might seem that this would be really hard, at least at the outset. But be very careful making architectural choices about what’s the fastest implementation technique when you’re only examining one user story. In an engineering discipline, the important part to optimize is not how quickly we can build the first screen, it’s how quickly we can build the 100th screen, taking into account all the coupling we created while building the previous 99 screens.
What we want is a sustainable pace, meaning the ability to develop and deploy features at a rate that we will be able to maintain for many years.
The only time you should optimize for the early stage is if you are building a quick and dirty throwaway prototype. In that case you shouldn’t be doing any of this microservices stuff. But then you must have the maturity and discipline as an IT organization to actually throw it away.
A microservice approach, focused on long-term sustainability, does actually tend to scale quite well. One reason is because there isn’t just one monolithic database anymore (which is really hard to scale). Instead, by having each microservice with its own micro-database – queries can run in parallel over smaller sets of data resulting in much better performance as commands don’t end up locking out other transactions.
Also, the architecture of each microservice doesn’t need to be identical to others.
You may have one that is layered using a standard SQL database. Another may be more sharded in nature using a document database. Another may use a graph database to deal with a domain that is much more about the relationships between the various pieces of data as opposed to just big piles of data. Different microservices may even leverage different programming languages. The decoupling between microservices allows you to use the appropriate tool for each job, rather than trying to operate off of a single suboptimal standard enforced system-wide.
After we filter through all the hype, we can see that we have a lot to gain by applying a rational microservices architecture to our systems.
By abandoning our attempts to decouple the layers in our architecture, we can instead focus on creating conceptual service boundaries that span multiple software systems and multiple process boundaries. We can concentrate on achieving high cohesion vertically within our layers, and low coupling horizontally between data that is conceptually unrelated.
We can have cross-functional teams working on each microservice, delivering the same business capability across the enterprise, leveraging their inherent domain expertise in that business capability instead of reinventing the wheel within each system boundary.
We can stop “building systems,” with the narrow focus that implies, and instead compose them from reusable building blocks as requirements dictate.
It is a challenge to be sure, but with this architecture in place, we will be set up for long-term success, able to continuously build and deploy new business functionality at a sustainable pace for years and years to come.
After all, wasn’t that the goal all along?
IBM: From Theory to Practice – https://www.redbooks.ibm.com/redbooks/pdfs/sg248275.pdf
Infosys: A New Application Paradigm – https://www.infosys.com/digital/insights/Documents/microservices-application-paradigm.pdf
Microservices: yesterday, today, and tomorrow-