Mark Needham

Thoughts on Software Development

Archive for the ‘Micro Services’ Category

Micro Services: Where does the complexity go?

with one comment

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!

Deployment

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!

Written by Mark Needham

February 28th, 2013 at 12:00 am

Posted in Micro Services

Tagged with

Micro Services: Readme files

with one comment

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!

Written by Mark Needham

February 25th, 2013 at 11:58 pm

Posted in Micro Services

Tagged with

Micro Services: Plugging in 3rd party components

with 2 comments

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:

 Micro services

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.

Written by Mark Needham

December 4th, 2012 at 11:38 pm

Posted in Micro Services

Tagged with

Micro Services: The curse of code ‘duplication’

with 8 comments

A common approach we’ve been taking on some of the applications I’ve worked on recently is to decompose the system we’re building into smaller micro services which are independently deployable and communicate with each other over HTTP.

An advantage of decomposing systems like that is that we could have separate teams working on each service and then make use of a consumer driven contract as a way of ensuring the contract between them is correct.

Often what actually happens is that we have one team working on all of the services which can lead to the a mentality where we treat start treating the comunication between services as if it’s happening in process.

One of the earliest lessons I learnt when writing code is that you should avoid repeating yourself in code – if you have two identical bits of code then look to extract that into a method somewhere and then call it from both locations.

This lesson often ends up getting applied across micro service boundaries when we have the same team working on both sides.

For example if we have a customer that we’re sending between two services then in Java land we might create a CustomerDTO in both services to marshall JSON to/from the wire.

We now have two versions of the ‘same’ object although that isn’t necessarily the case because the client might not actually care about some of the fields that get sent because its definition of a customer is different than the provider’s.

Nevertheless if we’re used to being able to working with tools like IntelliJ which let us make a change and see it reflected everywhere we’ll end up driving towards a design where the CustomerDTO is shared between the services.

This can be done via a JAR dependency or using something like git sub modules but in both cases we’ve now coupled the two services on their shared message format.

I think the ‘duplication’ thing might be less of an issue if you’re using a language like Clojure where you could work with maps/lists without transforming them into objects but I haven’t built anything web related with Clojure so I’m not sure.

As I understand it when we go down the micro services route we’re trading off the ease of working with everything in one process/solution for the benefits of being able to deploy, scale and maintain parts of it independently.

Perhaps the problem I’ve described is just about getting used to this trade off rather than holding onto the idea that we can still treat it as a single application.

I’d be curious to hear others’ experiences but I’ve seen this same pattern happen two or three times so I imagine it may well be common.

Written by Mark Needham

November 28th, 2012 at 8:11 am

Posted in Micro Services

Tagged with

Micro Services: A simple example

with 4 comments

In our code base we had the concept of a ‘ProductSpeed’ with two different constructors which initialised the object in different ways:

public class ProductSpeed {
  public ProductSpeed(String name) {
    ...
  }
 
  public ProductSpeed(String name, int order)) {
 
  }
}

In the cases where the first constructor was used the order of the product was irrelevant.

When the second constructor was used we did care about it because we wanted to be able sort the products before showing them in a drop down list to the user.

The reason for the discrepancy was that this object was being constructed from data which originated from two different systems and in one the concept of order existed and in the other it didn’t.

What we actually needed was to have two different versions of that object but we probably wouldn’t want to name them ‘ProductSpeedForSystem1’ and ‘ProductSpeedForSystem2’!

In Domain Driven Design terms we actually have the concept of a ‘ProductSpeed’ but in two different bounded contexts which could just mean that they come under different packages if we’re building everything in one (monolithic) application.

However, we could see from looking at the way ‘ProductSpeed’ initialised from the second constructor was being used in the application that it didn’t interact with anything else and so could easily be pulled out into its own mini application or micro service.

We’re actually building an API for other systems to interact with and the initial design of the code described above was:

Api before

We get a product from the product list (which is sorted based on the ordering described!) and then post a request which includes the product amongst other things.

After we’d pulled out a micro service it looked like this:

Api after

The choice of product is actually a step that you do before you make your request to the main API whereas we’d initially coupled them into the same deployable.

These are the advantages I see from what we’ve done:

  • We can now easily change the underlying data source of the products micro service if we want to since it now has its own schema which we could switch out if necessary.
  • It takes about 5 minutes to populate all the products and we run the script to repopulate the main DB quite frequently. Now products can be loaded separately.
  • Our code is now much simplified!

And some disadvantages:

  • We now have to deploy two jars instead of one so our deployment has become a bit more complicated.

    My colleague James Lewis points out that we’re effectively pushing the complexity from the application into the infrastructure when we design systems with lots of mini applications doing one thing.

  • Overall I think we have more code since there are some similarities between the objects in both contexts and we’ve now got two versions of each object since they’re deployed separately. My experience is that sharing domain code generally leads to suffering so we’re not doing that.

Written by Mark Needham

March 31st, 2012 at 9:06 am

Posted in Micro Services

Tagged with