Embracing microservices

Microservices. This is likely one of the most popular buzzwords in software development today; but what does it actually mean? Microservices are, in many ways, a direct response to the challenges of monolithic applications. Instead of a single, large service that grows and grows over time, a microservices architecture comprises smaller, focused services that perform a single task. This is similar to how we might think of a class in object-oriented programming as doing one thing, or modeling a single piece of domain knowledge.

In any large system, it is likely that there are multiple different areas of the domain that can be broken down and separated out. This could be things such as authentication, user registration, video encoding, or content delivery. In a monolithic application, these would likely be managed by the same large service, but with a microservices approach, each of these domain tasks could be managed by their own small service.

How does this increase in services improve the overall effectiveness and efficiency of the system? To begin with, smaller and more focused services are easier to understand, maintain, and therefore more easily owned by a specific individual or team. Because microservices are specialized and have clear responsibilities, it makes it easier to understand how a change in one microservice will affect others in the system. Fixing a bug, adding functionality, or increasing performance therefore becomes a much more manageable task, thereby increasing the likelihood that the service scales well over time.

By focusing an individual service on a specific task, it becomes very clear where to look when that task is experiencing performance degradation or other problems. Individual services can be more easily monitored, debugged, and improved because they are largely isolated from the rest of the system. What's more, because they are isolated from the system, they aren't necessarily tied to the same types of monitoring tools as the rest of the system. If a particular service requires a specialized tool, it can be applied locally to that single service.

This notion of specialized tooling doesn't just apply to performance monitoring. In reality, because each service is self-contained and ideally exposes a common set of APIs for other services to interact with, it doesn't matter how the service is built.

In a microservices architecture, it's possible for individuals and teams to build their services with whichever tools, languages, and frameworks they see fit. This enables developers to adopt new tools, experiment with new languages, and generally work toward finding the ideal tech stack for their organization.

The freedom provided by focused individual services can lead to a more scalable system. As individual services are fixed more quickly and more often, and performance bottlenecks are monitored and fixed, the overall system improves. When a service needs to be replaced, the rest of the system may not even know about it. Teams are more free to focus on their own services without as much concern for how it may impact unrelated services. All of this can lead to faster teams, more performant services, and ultimately a better application.

While this microservices architecture has many benefits, it has its drawbacks as well. One of these is that, in enabling services to be developed with whatever languages and frameworks a developer sees fit, it opens us up to endless possibilities for how to build our microservices. This potentially increases the complexity of the overall system by increasing the number of languages and frameworks required to maintain that system. However, it's also very powerful because it enables developers to use whatever tools they are most comfortable with when building their services.

In the next section, we're going to use this freedom by focusing on how we may begin using Kotlin to build services within our microservices architecture.