Microservices has become a catch-all term in the industry used to describe anything from architecture patterns to actual service implementations.
With such a broad spectrum, it can be daunting to know what it is, what it isn’t, and maybe more importantly, why we should care.
In this post, I’ll provide an overview of three kinds of Microservices that I have observed in client architectures. I’ll also discuss specific examples of their purposes and a method to implement each one.
Before we dive in, it’s important to note two things: this is not the only way to implement these services, and these are not the only Microservices out there. The goal of this post is to identify 3 of the most common Microservices I’ve seen often and to walk through how they can be successfully implemented.
These Microservices are:
- Domain Microservices
- Integration Microservices
- Unit-of-work Microservices
With more specific examples of each one and their sample implementations, I will be able to provide some insight into why caring about what kind of Microservice you have or are dealing with can help you develop, define, and support these ubiquitous services.
Without any further delay, let’s begin by defining the “Microservices!”
Since I am a software architect, I tend to define Microservices as a pattern. I’d describe Microservices as a method to decompose a monolithic application into smaller, more manageable parts.
If possible, the service boundaries should follow the domain-bound context of the underlying data model to allow each service (and all its supporting data) to scale and function independently of other services. These services then communicate through protocols like HTTP, gRPC, etc… depending on the constraints of the system and its messaging.
To describe the actual service implementations, I define them as one of three things depending on the type of microservices.
- Domain Microservices: loosely coupled services that collaborate with other services via a well-defined API to provide a collection of related functionality
- Integration Microservices: an abstraction that allows interaction between potentially unrelated applications as is the case with multiple COTS (Commercial Off The Shelf) packages
- Unit-of-Work Microservices: a stand-alone service providing a single set of functionality
Now that we have a broad understanding, let’s dive into our first type, Domain Microservices.
To be explicit, I define Domain Microservices as loosely coupled services that collaborate with other services via a well-defined API to provide a collection of related functionality.
For enterprise clients, these microservices are the ones I often see developed as custom code artifacts. These can be .NET Core services, Spring Boot services, or even Node.js services.
It seems that services that handle an entire domain of functionality tend to be better approached with custom development. This is most likely due to the high degree of business logic expression in each domain.
Now to give an example. Let’s consider a common contrived domain of a person.
In a typical monolithic application, if you’re lucky, the person-related functionality may be defined in a class or set of classes. However, most often, it’s scattered about the code base and added to different areas as the application evolves.
This leads to a high potential for duplication of functionality and problematic updates if the properties of the person mutate over time. Definitely a headache!
That’s where Domain Microservices comes in. Typically, enterprise clients start by decomposing their monolithic application into the domains present in their system. This boundary seems the easiest to follow with code and data as the definitions of each domain are likely already in place or easily created.
Most Domain Microservices are implemented as a RESTful set of services that communicate through HTTP protocols in my clients.
These services provide functionality for multiple endpoints on a well-defined API. The API often has been described and/or defined using Swagger or a similar tool that clearly shows what the endpoints expect and return. These endpoints often expand as functionality is added either by increasing the dictionary of properties or by adding another endpoint.
By decomposing these domains into microservices, the extension model to add functionality is clearly defined and can be very predictable for development teams to plan. In fact, in my experience, most agile development teams in enterprises are building either monolithic applications or these types of Microservices.
A Quick Recap
To review, Domain Microservices tend to be implemented as custom development projects because of the amount of correlated functionality and the desire for additional functionality.
Why should you care about this type of Microservice? Most likely, the codebase and development team structure will be diverse and could be distributed. The Microservice would be developed by a team instead of a single developer, which may impact any efforts to support, document, or scale these services.
Also, because these services tend to address multiple pieces of functionality, there may be some archeology involved to determine what service does what – especially if there is a problem that is being addressed.
This can help if you are inheriting the support and maintenance of one of these services or if you are on a team that is tasked with the development of this type of functionality.
I define Integration Microservices as an abstraction that allows interaction between potentially unrelated applications, as is the case with multiple COTS (Commercial Off The Shelf) packages.
In enterprise clients, I most often see these types of services implemented in a larger, prescriptive ecosystem like an ESB or an API Gateway. Integration Microservices are usually implemented in these low-code environments because of a desired or required integration.
An example of Integration Microservices is using MuleSoft and its corresponding low-code services to integrate with and pull data out of SalesForce.
Since MuleSoft is owned by SalesForce and has a pre-based connector to SalesForce out of the box, this is a common approach for enterprises that require SalesForce data to be accessed by their other applications.
Instead of custom dev efforts in this area, these low-code Microservices make the development and deployment of functionality very straightforward and rapid.
Since other concerns like security, logging, scaling, etc. are handled by the application backplane (in this case MuleSoft), developers can be junior level.
It is important to note that the opposite can also be true, though. There may be a need for a MuleSoft/platform expert who essentially is a senior engineer focused on the MuleSoft/platform space. This is key because as you engage with these teams or develop these services there may be a very prescriptive SDLC due to the opinionated nature of the platform.
Of course, MuleSoft is not the only platform being used. Other ESB/API Gateways I have encountered with regularity are Del Boomie, Apigee, and Web Methods. There are new tools debuting and legacy tools being repurposed all the time, but these are the ones that I see regularly.
A Quick Recap
So to review, Integration Microservices are often implemented in low-code implementations that provide pre-baked connectors and facilitate quick integration with disparate systems. In some cases, all the COTS packages in an enterprise can have their data exposed via one of these platforms.
Since these platforms handle the sidecar and cross-cutting concerns, the development of these services can proceed very quickly and myopically in scope. They are often implemented because of the sheer amount of COTS packages in an enterprise.
Instead of propping up custom dev teams to try and extract/expose data in these systems, the integration problem has often been solved through these ESB/API Gateway platforms.
The selection of the platform itself depends on the system integrations required, the overall cost model, and the skill level required for Microservice development.
So, why should you care? There is a large potential for a high level of low-code Microservices being implemented. This can affect how you approach support or development of these types of Microservices.
Often, troubleshooting and debugging these services can be just as prescriptive as development. This is important to take into account because the processes may not align with typical development or support models. Instead, they may be proprietary or specific to the platform.
It is also key to note that these low-code Microservices may not be developed in traditional development languages. Often, these platforms have their own proprietary code language.
This is a two-fold strategy for these platforms. One, they become a skill set all their own (a MuleSoft developer cannot necessarily build out Web Methods services without training and additional investment). Two, it can lead to easier adoption for non-technical resources, especially if the custom language is more like a natural language.
Knowing this can help you if you are being tasked with developing one of these Microservices, or can at least help you engage with teams building these Microservices. If development is required, you may need additional training or reference material if you have built integrations in the specific platform.
Our final Microservice is the Unit-of-Work Microservice. I define this one as a stand-alone service providing a single set of functionality.
In my enterprise clients, I most often see these Microservices implemented as serverless bits of cloud functionality. These lend themselves especially well to Azure Function Apps or AWS Lambdas that are essentially a single “function” compiled as a code artifact.
Examples of this would include a function that initiates a batch process or returns a very specific data set that is requested at a volume much higher than other areas of the application.
These Microservices are best implemented as stateless and asynchronous “fire and forget” bits of functionality. This serverless implementation allows the function to scale independently of the rest of the application.
These Microservices only perform a single function, like their namesake, a defined unit-of-work. This can be a great method to modernize legacy applications in place. Additional functionality is often not a completely new domain but just an untapped portion of an existing one.
Instead of modifying existing legacy code, which usually is a source of pain for the enterprise, the new functionality can be implemented in a stand-alone and independently scalable serverless function. At enterprises, these functions are developed and deployed by a single developer since their scope is often very small and clearly defined.
A Quick Recap
To review, Unit-of-Work Microservices are often implemented as cloud-based serverless functions like AWS Lambdas or Azure Function Apps. In enterprises these are often used to modernize legacy applications in place – without having to address the legacy code itself in most cases.
You should care because these Microservices are the product of a single developer and deployed in a cloud platform. This will be key if you have to support one as there will only be one source of truth for what the code does and how it is deployed.
Also, if you have to develop one of these Microservices, there may be a specific cloud platform that the code will need to be deployed to. This can affect what SDKs are needed to perform the development as well as the actual deployment activities.
Since these Microservices are often extensions of existing functionality, there also may be well-established teams that have opinions on what the code should do and how it should perform. This can be critical to the successful development of one of these Microservices.
In this blog, we reviewed three types of Microservices (Domain, Integration, and
Unit-of-Work) that I have seen implemented at enterprise clients with regularity. I provided a definition of each type and sample implementations to help visualize how you might encounter them.
I also provided some information on why you should care about each, including what the team interactions might look like and what the development ecosystem might include.
Obviously, this is not a totally exclusive list, and you may encounter several different mutations of Microservices in your career. This is simply my experience with several enterprise clients and the similarities that go beyond coincidence to be commonplace Microservices.
If you see one of these Microservices in the wild, I hope that now, you are better equipped to support, develop, or simply define them in your engagements.
If you encounter other versions with regularity, please comment on this article and provide examples. Sometimes as an enterprise architect I can get very narrow in my view of the software multiverse.
As always, if you are beginning to implement microservices in your organization, or if you have pain points around scalability, deployability, maintainability, or performance – Keyhole Software is here to help and has consultants who have done whatever you are trying to do. If you need help, have questions, or just need bandwidth – we can help!
If you have any specific feedback or questions about his blog post, please be sure to comment on this post. This is still a weird time in COVID-land, so I will end by wishing you all good health, good designs, good code, and good life!
Peace and hair grease,