Software often seems like a benign version of Game of Thrones, in which any dominant or ascending technology/methodology is constantly challenged by newer and more attractive rivals. So as soon as microservices entered the mainstream, it didn’t take long until some developers saw it as flawed, and proposed nanoservices as a replacement. In this article, we ask why the move to breaking down software into smaller and smaller pieces is a good idea. Then, we explain what micro- and nanoservices are, what they offer, and their individual pros and cons. We conclude by comparing the two different approaches and recommend the path you should take.
Monoliths: Large but Fragile
A monolith is a large rock, or an impersonal structure, regarded as intractably indivisible and uniform. Monolithic software is a one-size-fits-all solution that tries to do multiple things in one place. The application may include numerous components and subcomponents, these are tightly coupled with complicated and interconnected code. This code is compiled and the end result is often a single executable binary file. In addition to taking up increasing amounts of disk space, monolithic applications have a number of problems. Many applications are delivered as a single, binary file; this makes debugging and troubleshooting a nightmare. If you are lucky, you will have access to both the original source code, and the developers that wrote it. In some rare cases, you will also have access to decent documentation and test code. In most cases, you will count yourself lucky that the original team used source control, or that somebody can remember the network share where some of the legacy code was backed up to. Being hard to maintain means monolithic apps are hard to scale, it also makes them hard to adapt to new models, such as the cloud and distributed computing.
Small is Beautiful: The Rise of Microservices
Microservices were created to overcome the issues of monolithic software, and to offer a better solution for building distributed, cloud-based applications. A microservice decomposes a monolithic application into a collection of individual, loosely coupled services. These services should be organized by the business processes they handle, should be easy to test, and independently deployable.
According to microservice advocates, this results in software that is designed to meet specific needs. Not only does this avoid the creep and bloat associated with the monolithic approach, it also shortens development time and deployment cycle. By accident or design, this makes microservices a perfect fit for current DevOps practices, such as continuous integration, deployment, and delivery.
The fact that microservices are smaller and more focused than their predecessors makes them easier to maintain, scale, and test. Moreover, since they are focused on achieving a specific outcome, they are isolated from other services. So, by building and deploying microservices you are far less likely to experience the kind of cascading problems that afflict monolithic apps. Another advantage of the microservices approach is that you don’t have to build each microservice the same way. In other words, if you are building a big monolithic app it makes sense to pick a single language and development stack. You could write your microservice in Python and MongoDB Atlas, NodeJS and Postgres, or anything you prefer, even Cobol and DB2.
Not Small Enough: Introducing Nanoservices
Nanoservices are everything you love about microservices, but smaller. One of the problems of microservices is that they are micro in name only. Yes, they are smaller than monoliths, but there is no standard definition of what a microservice is supposed to be. In many cases, it would seem that a microservice is just another name for any web service or API.
By design, a nanoservice is designed to do one thing only, and expose that thing as a single API endpoint. This may seem like a disadvantage when compared to microservices, but nanoservices are designed to be discoverable, by and for each other. This means that if you need your nanoservices to do more than thing, you can extend them by linking them to other, existing nanoservices. Nanoservices share many similarities with package managers, such as Node’s NPM or Python’s PIP, by being highly self-contained and reusable. Unlike their bigger siblings, they not only include code, but also documentation and any relevant dependencies. Nanoservices also contain all the relevant infrastructure information that can be used to automate the service’s deployment process.
The perceived benefits of nanoservices extend beyond their technical advantages over microservices. By being smaller than microservices, nanoservices make it possible for a number of different teams to work on one or more services at any given time. Each nano service can be built according to its own timetable and released according to its own independent release schedule. In theory, these smaller, safer, and more frequent releases should result in fewer breaking changes. Once released, nanoservices provide an extra level of flexibility because they let you chain together different services in the same way you pipeline different Unix shell scripts.
The Bigger Picture
Microservices are generally a big improvement over monoliths, and nanoservices are even better. However, both approaches share similar issues. One common problem is similar to solving a problem with Java, that instead of fixing the original issue you created a problem factory. So while it seems to be a good idea to break down a big app into many smaller services, the end result is that you end up creating multiple smaller problems. It is also important to bear in mind that building a distributed system will add another level of complexity that is both hard to build and even harder to manage. Another common problem is the risk of wasted effort by duplicating services that have already solved your specific issue or similar problems.
Both micro- and nanoservices overcome many of the limitations of monolithic software, they create variations of existing problems and create some new ones of their own. For example, on the whole microservices can be very resilient, but they still have dependencies so they can trigger or experience the same sort of cascading failures. But, in both cases you could end up creating huge numbers of them. The more services you create the bigger the infrastructure and network resources you need to support them.
Nanoservices also have their own unique issues. The additional isolation you can achieve with nanoservices might seem enticing, but in practice is very hard to pull off. Ideally, a nanoservice should be as lean and mean as possible, but will you need to create additional services to provide the required functionality? This brings us to a related issue, making things small is not an end in itself, and you will end up sacrificing usability to meet some abstract size standard. Moreover, like quantum mechanics, the smaller scale you operate on, the harder it is to know what’s truly going on at this scale. So, nanoservices might perform better and be more reliable than microservices, but their smaller size makes them much harder to monitor. Finally, if nanoservices are both more numerous and harder to monitor than existing alternatives, doesn’t this make them an ideal malware vector?
Conclusion: How to Choose the Best Path
Both service types are designed to deal with the shortcomings of the previous incumbent, and deal with the new challenges of cloud-based distributed apps.
When it comes to picking which to use, the fact that microservices have been around longer is a clear advantage. As a result, they are a known quantity, and have been battle tested by major players such as AWS and Netflix. There is a wealth of available resources and they work well with a range of existing technologies. On the downside, they are not always suitable for every application. There is no clear definition between what is and what isn’t a microservice. Microservices can grow as large as the monolithic solutions they replace. They also lack a clear deployment path and are hard to discover. Despite these limitations, microservices are a known quantity and we recommend them as the better option for larger more conservative organizations.
Nanoservices are much newer, but have a number of clear advantages. They are smaller, more focused, and provide both greater isolation and flexibility. In addition, nanoservices can discover and be discovered by other services. Another key advantage is that they have a number of built-in features that make them easier to deploy. Being the new kid on the block is not always an advantage, and microservices are more of a known quantity. Nano services fix many of the issues of microservices, but also have many of the same issues on steroids. That being said, nanoservices have a lot of promise, but it’s still early. However, if you like to live on the bleeding edge, then go for it.