Sunday 19 August 2018

Divide and Deploy


Certain patterns and practices can come and go within software engineering, either becoming defunct, disproven or otherwise going out of fashion. However, divide and conquer as epitomised by principles such as Single Responsibility has always been a strategy to deliver scaleable and robust solutions.

It is the application of this mindset that lead to the advent of microservices. This technique divides an application into a group of loosely coupled services each offering specific, cohesive and a relatively narrow set of functionalities.

Any architecture or pattern when described succinctly can sound overly simplfied, the description in the previous paragraph doesn't enlighten the reader to the devil in the detail when it comes to the implementation and application of a pattern such as microservices.

This post also won't cover these topics in enough detail to fully arm the reader but it will attempt to point in the right direction.

What is Micro?

The effectiveness of any microservices approach will be reliant on developing the correct segregation of duties for each service, this provides the modularity that is the basis for the success of the pattern. The reason this aspect of the approach is non-trivial is because it is possible for microservices to be too small.

This can create increased cognitive load on those tasked with working on the system as well as creating a ripple effect when changes are required as each service becomes less independently deployable due to its increased dependencies on other services to achieve an outcome.

A good starting point can be to align your initial design to the agents of change within your organisation, this might be areas such as ordering, billing, customer or product discovery. This can enhance the benefit of the scope of change being contained whilst also allowing engineers and the rest of the business to have a common view of the world.

Another more technical analysis can be to asses which is more time consuming, to re-write or to re-factor? A sweet spot for a microservice and an indication of its scope is whether it would be quicker to re-write or to re-factor when a wide reaching change is required.

This isn't to say that it is optimal to be continually re-writing services but the freedom offered by an architecture where this is the case can be a great aid to innovation and the effective implementation of change.

Micro-Communication

Once we have a suite of microservices how can they be drawn together to form a coherent and competent system whilst remaining loosely coupled? Two possible solutions to this conundrum are REST APIs and an Event Bus.

These two different approaches to communication between services fulfil the differences between explicit communication and a loose transmission of information.

On occasion two microservices will need to explicitly communicate, as an example an ordering service may need to communicate with a payment service and require an immediate response. 

In these situations services can present a RESTful API surface to allow this kind of interaction. Intrinsically linked to this approach is the concept of service discovery, there are various approaches that can be taken but essentially this involves microservices registering their capabilities and the APIs they offer to clients to allow a system to form dynamically as new services are introduced.

This kind of communication exists where interactions between services are necessarily pre-defined but sometimes it is desirable and advantageous to allow these interactions to be looser.

An event bus offers this capability by allowing services to broadcast the occurrence of certain events and allowing others to react to those events without having to be aware of the source.

Following a similar example the same ordering service on successful completion of an order might broadcast this as an event so that services that handle communication with customers can take the appropriate action. The loosely coupled nature of this communication allows behaviour to be easily changed without the need for refactoring in the service handling the initial action.       

Micro-Deployment

So now we have our collection of properly sized and loosely coupled services how do we manage their deployment into our environment?

A key element of microservice deployment is independence, a sure sign that a microservices architecture is flawed is when it is necessary to deploy a number of services concurrently. This speaks to strong coupling caused either by a tightly coupled domain or an incorrect segmentation of responsibilities. 

A lack of independence also negates the intrinsic promotion of a CI\CD approach that microservices when applied correctly can offer.

Independence of deployment when combined with a load balanced blue\green approach also creates an environment where changes can be gradually introduced and quickly rolled back if problems present themselves. This is in contrast to a monolithic architecture where a small problem in one area may result in working changes in other areas having to be rolled back.

Microservices is a pattern that comes more with a serving suggestion than a recipe. Its proper application cannot be applied via a cookie cutter methodology. There are certain aspects that are universal but a good architecture will only be designed by understanding how they can be applied to your particular situation whilst keeping an eye on the successful realisation of its benefits. Many of these benefits will enable you to make mistakes by giving you the freedom to reconfigure, refactor and realign your architecture without causing widespread disruption.


No comments:

Post a Comment