Have you noticed what a cornucopia of buzz-words the technology world is? It seems that we’re in a never-ending quest to put as many words before "-driven development" and "-oriented architecture" as we can. One such term that’s been thrown around for the last few years is "microservices." The problem is that there are a lot of opinions about what they are and how to do them right. A further problem is that many of these opinions and definitions have the correct intent while differing a bit from one another. So, let me further stir the pot by now offering you my opinion. I’ve always tried to be a realist and not fall into the hype of the new "shiny coin." I try to concentrate on what can truly bring value to my customers. I’ve found true value in approaching my designs using microservices to different extents in different scenarios, but I’ve approached it a little differently from what you may have read elsewhere. I’ve approached things in a holistic fashion.

Microservices are not really a particular type of service; they’re a part of an architecture that makes the services, the act of calling the services, and the clients that call the services, behave a certain way and provide certain characteristics to an application. The more accurate definitions and explanations of microservices I have seen are those that approach it from an architectural perspective. I’m not implying that microservices require a tight coupling with the application that consumes them. But I am saying that microservices are as much about the architecture of a system as they are about the implementation technology and the tools used to create them. The goal of this article is to give you clarity in understanding microservices by way of an overview of their characteristics and that of an architecture that implements them. How the concepts I’m going to discuss are implemented remains a large and complex topic, and one of possibly several potential future articles.

Microservices are part of an architecture that makes the services and clients behave a certain way and provide certain characteristics to an application.

If you’re asking yourself, "do we really need another description of microservices," I’ll tell you why I think the answer is yes. This is large topic with a number of different actors and ways to implement those actors. Learning about various points of view has always helped me take an eclectic stance and adopt ideas from more than one scenario. I hope, if you do the same, I’m contributing to that.

Looking at the Big Picture

If you’ve made the transition from developer to architect, whether in a full- or part-time capacity, the concept of the "big picture" should not be strange to you. As an architect, one of the tasks that falls under my responsibility is to talk to the developers across the entire stack and be mindful of what their needs are, both individually and collectively. How are service boundaries defined? Are services too coarse or too fine? How are services accessed? What parts of a client are dependent on another? How much can fail on the service-side before the entire client-side is rendered useless? These are just a few questions that architects ask when looking at building a new system. In fact, these are important questions when looking at an existing system that may require modification or even overhaul.

So, can microservices benefit the system you’re designing? There are many who say absolutely. But you can’t really know without having a good understanding of what they are, how they’re accessed, and if your application can be decomposed to accommodate them. And then there is the matter of the technology implementation choices you face. This is looking at the big picture.

The "Micro" in Microservice

The biggest misunderstanding about microservices is the prefix the term uses: "micro." Linguistically, this implies small services. Really small services. That’s not exactly the case. Microservices are about orchestrating and decomposing a system into services that are loosely coupled and that encapsulate areas of volatility. When done correctly, yes, this results in smaller services that expose operations in as fine-grained logical groupings as possible. This is because in microservices, the service boundaries are closer to the center, resulting in a more specific responsibility. This is probably where the term "micro" comes from.

A microservice is designed to do a very specific thing and only that thing, and to operate as autonomously as possible.

The decomposition that leads to how many services to have and what they do differs greatly from system to system, as does the size of the service. If this sounds a lot like the good old Service-Oriented Architecture (SOA) that you’ve read about plenty in the past, that’s because microservices have been described as SOA done right. SOA is about breaking up a monolithic system into a set of coarse-grained, somewhat autonomous components and then distributing the hosting of these components, or services, for shared client access. Systems are now separated into areas of responsibility so they can evolve and be deployed independently and not compromise the entire application. This also has the advantage of eliminating quite a bit of responsibility from the client regarding things like database access and details of workflow steps that can now be housed, orchestrated, and exposed by a service layer. On the Microsoft stack, you’d typically use either WCF or Web API to write and expose services. A client can now be a lot "dumber" and need only to know where a service is and how to access it. With WCF, this is done with a client channel (usually crated by a proxy class); in Web API, it uses the HttpClient class. Of course, in the case of the client being pure JavaScript, services are limited to a REST implementation of some kind.

The biggest misunderstanding about microservices is the prefix the term uses, "micro.

More than likely, I haven’t told you anything you didn’t already know, so how are microservices different? Well, the immediate answer is that in microservices, the granularity of services gets finer, making microservices an evolution of traditional SOA, but it’s about much more. Let’s go back to my original statement about microservices being as much about architecture as they are about the implementing technology, and how I approach things in a more holistic fashion. This means I try to think about the entire application and how it will be laid out.

In traditional SOA, you think about services on the server side, obviously. You spec out your service decomposition there, but traditionally the client doesn’t take any of that into consideration. It tends to stay as far away from that design as it possibly can, with the expectation that it will be able to use the services later. When architecting a microservice-based system, this can change a little. I’m not saying that the services are designed to cater to a specific client. By no means should that be the case. The decomposition on the server side remains decoupled from whatever clients it services. What I mean is to give thought to how a client is broken out because that becomes important when you start introducing the technology that accesses services; as you’ll see, that’s a big part of a microservice architecture.

Client Composition

Did you think you’d be reading about client design when discussing services? Let me be clear. I’m not saying that microservices should be designed around their potential clients. I’m saying you should be thinking about them when architecting a complete system that will use microservices. Now, before some of you start yelling loud enough to reach me here in New Jersey, let me elaborate on that statement. If you’re talking about the services exclusively, the clients are, for the most part, irrelevant. But I’m talking about a larger picture here, remember? I’m talking about organizing a composite system with regard to both the services and the clients. The relationship here is loose, but it’s a relationship nonetheless.

Most definitions of microservice-based solutions discuss fault tolerance to some degree, as I’ll also do later. But what about complete failure of a service? On the service side, this may very well affect other services, either crippling them partially or rendering them completely useless. This would obviously affect the client as well, but it certainly shouldn’t render an entire client useless. Although there’s service decomposition that takes place when the service layer is designed, there’s also decomposition of a client so that failure of a service or groups of services manifests on the client in a controlled fashion, making only a part or parts of the client inoperable—hopefully temporarily of course. Note that the decomposition of a client is not particularly a new concept, nor one that is tied to the service-oriented world. This is one of the things that leads to what is sometimes referred to as a composite application.

A Practical Example

Let me put this into perspective using a real-world example in a business sector with which we are all familiar: eCommerce.

An eCommerce system, such as Amazon.com, can have an entire service layer powering it. The decomposition of all the needed functionality resulted in groups of services that handle areas such as User Account, Shopping, and Checkout. In fact, these areas can be further broken into sub-areas, each somewhat autonomous. The User Account area can consist of Account Creation, Login, Profile Management, and management of a user’s definition, all specific to this system. In the case of Amazon, this could include the one-click setting, Kindle devices, etc. The Shopping area can be broken out into Product Browsing and Building a Shopping Cart. And even Product Browsing can be split into browsing various product categories. The Checkout area, which, on the surface, may seem like a self-contained area in its finest grained form already, can allow the as-is checkout versus the changing of checkout options, such as credit card or shipping address.

All of these areas, sub-areas, or sub-sub-areas I’m mentioning have their own service or small groups of services that handle the fulfillment of tasks that cover that area’s responsibilities. The finer grain I can decompose service-side areas into, the more "micro" my services appear, right? Yes, but that fine-grain decomposition alone doesn’t give this eCommerce system a microservice architecture. Some of these services may depend on the availability of others. Some of this dependency may even span areas of composition. An infrastructure is necessary to make these determinations. As I’ll talk about a little later, this is one of the key characteristics of a microservice architecture and it’s known as discoverability. Now let’s shift to the client a little bit.

All these areas, as I’ve called them, that are driven by services have some kind of manifestation on the client. More than likely it’s not a one-to-one relationship. For example, Product Browsing may be a part of the site that is serviced by several microservices. But the temporary failure of a service or a group of services that are needed for Product Browsing to operate shouldn’t affect the user’s ability to purchase what’s currently in the user’s shopping cart. And if the service that handles user login is down, the site should be able to accommodate shopping under an anonymous identity. Of course, the Checkout section of the site would be off line until the Log-in service is back up. And then, it would also rely on its own services being available.

Each part of the client must accommodate a failure in accessing the services it calls upon. The discovery facility to which I alluded earlier forms a large part in facilitating this. Discoverability is one of many characteristics of a microservice architecture. This and all the other characteristics I’m going to talk about have more than one type of implementation possibility. There are products on the market, free and otherwise, that assist in providing your architecture with said characteristics. I’m not going to point you to any specific solution in this article. In fact, in many cases I’ve written custom implementations to accommodate my particular needs. My goal here is to make you aware of characteristics that your architecture and the actors within need to have if you want to design a clean, scalable, and robust microservice-based solution.

Microservice Architecture Characteristics

As you’ve probably figured out by now, fully embracing microservices is about more than just accessing a smaller service. A system properly architected to be microservice-based needs to look at having certain characteristics, some of which apply only to the services, but others to the system as a whole. Keep in mind that not only does the implementation of each of the characteristics I’ll discuss vary, but also a microservice architecture isn’t necessarily limited to only these characteristics. In fact, even the depth to which each of these carries can vary among implementations. This list represents items that you find in every well thought-out microservice architecture.

  • Redundant hosting
  • Isolation
  • Dependency checking
  • Service discovery
  • Easy client access
  • Failover and exception management

I’ll limit each item to a conceptual explanation as anything beyond it both outside the scope of this article and beyond the room we have. You may find that these characteristics overlap a bit.

Redundant Hosting

Good services shouldn’t be limited to one-location hosting. For systems to scale successfully, you don’t want the same service in the same process in the same computer being the only point of availability to clients. But of course, hosting the same service from multiple addresses may introduce the question of which one to use. This is going to depend on how your services are hosted. If you’re using virtual containers, such as Docker, your addressing may only differ by a host name. Whereas if you’re simply hosting services on the same computer but different processes, a port name may differentiate the address. A load balancer may or may not exist in front of a group of the hosted services, or a discovery service may be the differentiator.

There’s no exact right answer to this and there’s no one solution for how to handle it. Note that with regard to how many services a host should handle, the ideal answer is one. But when looking at the business space to which the service provides value, one service may take a dependency on another. Whether this multitude of services is grouped into a single host or each is provided with a host of their own is going to depend on your environment, discovery facility, hardware, and several other factors.

Isolation

A service or group of services hosted together should be exposed in a fashion that doesn’t put any other service or group of services at risk. This can only be guaranteed by isolating their hosting from one another, ranging from process isolation to computer isolation. If the desire is to have computer isolation in conjunction with deployment facilitation, this is where virtual containers can assist. But make no mistake, containers do introduce their own element of complexity.

Containers introduce their own element of complexity.

Dependency Checking

You can’t always guarantee that a service can or even should handle all its responsibility internally. This eventually leads to breaking that golden rule of reusability that you’ve been taught and have been practicing for years. A common task can easily be required by more than one service. Duplicating twice may be fine, three times may be acceptable, but twenty times is unfeasible and blatantly unmanageable. If one service is going to depend on another, the availability of the other needs to be checked. This can and should be handled by whatever discovery solution you choose but also, it shouldn’t be limited to the service in need. Ideally, a cli