Back in the olden days, everyone went nuts for Service Oriented Architecture. Many consultant dollars were made. Everyone temporarily forgot who Fred Brooks was (No Silver Bullet). Time moved on, the hype died down. But just like a Jeffrey – IT COMES BACK. Yes, I’m talking about micro-services.
Martin Fowler has a really nice piece on this topic: http://martinfowler.com/articles/microservices.html where he talks about the advantages of being at least familiar with the approach – especially when designing for cloud-based applications.
With that in mind, having a decentralised, distributed design was important to me as I map out the design for Argomi on the back of whatever receipts and envelopes I can get my hands on (I look forward to the day when tablets provide me the functionality of pencil and paper). However, I have now stumbled across a question I have previously agonised over: the shared class library.
If we are splitting up a design into pieces, then it seems obvious to want to have a class library shared amongst all services with business logic encapsulated and lots of nice code-reuse. The issue comes from the implicit coupling.
One of the ‘points’ of microservices is that each service is independent of the others, and can have its own release cycle – or be completely replaced with an improved version, and the other services don’t necessarily need to even know. This leads to articles like: http://www.simplicityitself.io/our%20team/2015/01/12/sharing-code-between-microservices.html which suggest not sharing anything – even class libraries – since changes may require all services to be upgraded at the same time. It also pretty much forces you to use the same technology for all services so that the class library can be shared.
My feeling right now is that avoiding a potential coupling is normally not worth the cost of reimplementing complicated business logic and that one should:
- Strive to design fixed interfaces and classes so basic interactions with the class don’t change over time.
- Make changes backwards compatible between versions (e.g. providing a default implementation for a new field) so that the library doesn’t have to be updated in all services exactly simultaneously, however;
- Don’t allow multiple versions of the library to run for longer than absolutely necessary. This is just a modern version of dll-hell, and leads to unnecessary mental load for all developers who need to remember which versions are out in the wild.
- For the same reason, unless absolutely necessary never create two interface points to the same function, with one simply acting as a pointer to the other so that original callers don’t need to be updated to consume a new interface signature.
Does anyone have any alternative experience they would like to share? Perhaps a shared class library that got out of control?
No discussion of microservices would be complete without linking to the fallacies of distributed computing.