Archive for the ‘micro-services’ tag
For the past year every system that I’ve worked on has been designed around a micro services architecture and while there are benefits with this approach there is an inherent complexity in software which has to go somewhere!
I thought it’d be interesting to run through some of the new complexities that I’ve noticed in what may well be an acknowledgement of the difficulty of designing distributed systems.
Interactions between components
One of the advantages of having lots of small applications is that each one is conceptually easier to understand and we only need to keep the mental model of how that one application works when we’re working on it.
With the big monolithic application all the code is together which makes it more difficult to make that separation and completely different concepts can end up getting mashed together.
On the other hand there is now complexity in the interactions between the applications which will often communicate with each other over HTTP using JSON/XML messages.
We now need to be careful how you go about changing these messages because we can easily break a client of out service if we change the name of a field for example.
That can be solved by running two versions of the service but that means we have the burden of maintaining two versions of the service!
Understanding how everything fits together
Despite the fact that you can choose to focus on one component at a time there are occasions where you need to know how everything works together.
For example we recently wanted to make changes to the way data is displayed on our results page.
This involved making changes to a backend CMS, making sure those propagated to a database which another service used, making sure the service’s client could handle the new fields we added and handling the new fields on the web front end.
In a big monolithic system we might use an IDE to help us navigate around the code and see how everything fitted together whereas when we have separate applications the only tool we have is text search!
Although in some ways deployment is easier because we don’t have to deploy everything when we make a small change, in some ways it’s more complicated because we have more moving parts.
We need to deploy components in the right order otherwise we’ll end up deploying a component which relies on getting a certain value from another component which it doesn’t get because the other component’s out of date.
Another thing to look out for is that we don’t make our services too fine grained otherwise we’ll end up being overwhelmed by how many applications we actually have to deploy.
Micro services are still cool!
Despite these disadvantages it wouldn’t have been possible to have our teams setup the way they are without splitting capabilities in this way.
We have 10 developers in 3 teams working across ~25 different applications. There’s some overlap between the applications but each team owns about 1/3 of the repositories and they tend to dominate the commits on there.
Another neat thing about the micro services approach is that it’s very easy to see which things need to happen in real time on the web application and which can be processed offline at a later stage.
I’m sure there are many more things to watch out for when choosing to design a distributed system but these are the things I’ve picked up in my short amount of time working in this area!
By my latest count I have around 15 different micro services/applications checked out on my machine which comprise the system that I’m currently working on.
Most of these are Ruby related so it’s easy to figure out how to start up a local copy because it’s either bundle exec rails server if it’s a rails application or bundle exec backup if it’s a sinatra/rack application.
The clojure applications follow a similar convention and we use rake to run any offline tasks.
Despite these conventions there is still a reasonable amount of knowledge around how to actually get these applications to work that remains in people’s heads but doesn’t necessarily have to.
Although talking to each other is generally a good thing, an exercise that we tried at GDS was to try and document in the README file what someone new to an application would need to know to get it working.
They then tried to get it up and running while only referring to the instructions but noted down anything that didn’t make sense or any steps which seemed unnecessarily manual and could be automated.
This was almost certainly more frustrating than having someone show you what to do but it scales a bit better and reduces what I think isn’t a high value conversation.
I recently came across a blog post Tom Preston Werner wrote a couple of years ago titled ‘Readme Driven Development‘ in which he goes further in suggesting that we drive out our applications from the README.
This document should stand on its own as a testament to your creativity and expressiveness. The Readme should be the single most important document in your codebase; writing it first is the proper thing to do.
I don’t know if we need to go this far but as we more towards a future where we’ll be working with lots of different applications it would be nice not to have to remember everything about them in our head!
Over the past few weeks I’ve been involved in conversations with different clients around micro services and one thing about this architecture that seems quite popular is the ability to easily plug in 3rd party components.
In one case we were talking through the design of a system which would calculate and then apply price optimisations on products. The parts of the system we were discussing looked roughly like this:
As per the annotations, one of the questions asked was whether it would be possible to start out with the assumption that each component would be custom built and then assess that decision after a few weeks.
An advantage of splitting each of the components into their own application is that we could reasonably easily plug in a 3rd party tool behind the boundary while keeping all the HTTP wiring as custom code.
This allows us to get going quickly and write simple stubs in place of the main logic of some of the components to begin with.
We can defer the integration/learning curve of the 3rd party component while we prove out the architecture as a whole. In addition we are not letting the 3rd party component drive the design of our system but instead allowing it to play a supporting role.
One final thing to note is that since each component is a separate application it’s much easier to have different teams working on each one than it would be if they were all contained in the same application.
There would need to be communication between teams around the design of contracts between the services but after an initial period of churn hopefully those would become reasonably stable.