Michael Feathers’ tweet about technical empathy packs a lot of wisdom into 140 characters. Lack of technical empathy can lead to a system that is harder to both implement and maintain since no thought was given to simplifying things for the caller. Maintainability is one of those quality of service requirements that appears to be a purely technical consideration right up to the point that it begins significantly affecting development time. If this sounds suspiciously like technical debt to you, then move to the head of the class.
The issue of technical empathy is particularly on point given the popular interest in microservice architectures (MSAs). The granular nature of the MSA style brings many benefits, but also comes with the cost of increased complexity (among others). Michael Feathers referred to this in a post from last summer titled “Microservices Until Macro Complexity”:
It is going to be interesting to see how this approach scales. Some organizations have a relatively low number of microservices. Others are pushing higher, around the 600 mark. This is a bit beyond the point where people start seeking a bigger picture. If services are often bigger than classes in OO, then the next thing to look for is a level above microservices that provides a more abstract view of an architecture. People are struggling with that right now and it was foreseeable. Along with that concern, we have the general issue of dealing with asynchrony and communication patterns between services. I strongly believe that there is a law of conservation of complexity in software. When we break up big things into small pieces we invariably push the complexity to their interaction.
The last sentence bears repeating: “When we break up big things into small pieces we invariably push the complexity to their interaction”. Breaking a monolith into microservices simplifies each individual component, however, as Eran Hammer observed in “The Fallacy of Tiny Modules”, “…at some point, someone has to put it all together and then, all the complexity is going to surface…”. As Yamen Sader illustrated in his slide deck “Microservices 101 – The Big Why” (slide #26), the structure of the organization, domain, and system will diverge in an MSA. The implication of this is that for a given domain task, we need to know more about the details of that task (i.e. have less encapsulation of the internals) in a microservice environment.
The further removed the consumer of these services are from the providers, the harder and less convenient it will be to transfer that knowledge. To put this in perspective, consider two fast food restaurants: one operates in a traditional manner where money is exchanged for burgers, the other is a microservice style operation where you must obtain the beef, lettuce, pickles, onion, cheese, and buns separately, after which the cooking service combines them (provided the money is there also). The second operation will likely be in business for a much shorter period of time in spite of the incredible flexibility it offers. Additionally, it that flexibility only truly exists when the contracts between two or more providers are swappable. As Ben Morris noted in “Do Microservices create extra challenges for distributed development?”:
Each team will develop its own interpretation of the system and view of the data model. Any service collaboration will have to involve some element of translation or mapping and will be vulnerable to subtle bugs that can arise from semantic differences.
Adopting a canonical model across the platform can help to address this problem by asserting a common vocabulary. Each service is expected to exchange information based on a shared definition of the main entities. However, this requires a level of cross-team governance which is very much at odds with the decentralised nature of microservices.
None of this is meant to say that the microservice architecture style is “bad” or “wrong”. It is my opinion, however, that MSA is first and foremost an architectural style of building applications rather than systems of systems. This isn’t an absolute; I could see multiple MSA applications within an organization sharing component microservices. Where those microservices transcend the organizational boundary, however, making use of them becomes more complex. Actions at a higher level of granularity, such as placing an order for some product or service, involves coordinating multiple services in the MSA realm rather than consuming one “chunkier” service. While the principles behind microservice architectures are relevant at higher levels of abstraction, a mismatch in granularity between the concept and implementation can be very troublesome. Maintainability issues are both technical debt and a source of customer dissatisfaction. External customers are far easier to lose than internal ones.
18 thoughts on “Microservice Mistakes – Complexity as a Service”
RE “When we break up big things into small pieces we invariably push the complexity to their interaction” – and this is very good because the previously implicit complexity is now explicit and it can be addressed with various tools, e.g. DSLs (BPMN, DMN, etc.). Of course, a different skill-set than for classic coding is needed. Like we had with PCBs – design of standard micro-chips was different from composing them into a particular PCB.
RE “To put this in perspective, consider two fast food restaurants: one operates in a traditional manner where money is exchanged for burgers, the other is a microservice style operation where you must obtain the beef, lettuce, pickles, onion, cheese, and buns separately, after which the cooking service combines them (provided the money is there also). ” – I think that in the second case it should one more microserve to collect all ingredients into burgers. Again, with a different skill-set.
Optimal governance of microservices is a solid architecture (ideally, enterprise-wide) governance with a proper delegation of some decisions to classic development teams.
Discussions on boundaries remind me of previous discussions about granularity. Such discussions are become irrelevant when you have a really flexible architecture, since in this is the case you are able to adjust the granularity within a few iterations (in a similar way to how jagged stones become rounded pebbles under the moving ice).
Making complexity explicit has value in that it allows for a winnowing to separate the inherent complexity wheat from the unnecessary complexity chaff. This, however, is a concern internal to the organization owning the application. When we force that complexity outward to the consumers of the services rather than providing an aggregated service that matches the concern of the consumer, then we risk customer satisfaction unnecessarily. Unless we are an Amazon, providing a platform where each customer custom codes a unique solution, providing more granular services just makes sense.
If the complexity is the result of the subtle play between microservices, I would label that “implicit” rather “explicit”. Within a single module, the complexity is exhibited in numerous ways, length, structure, etc. The complexities in service interactions become apparent only after you wire them up.
It depends on whether it’s visible to clients or not. Forcing that complexity outward complicates use of the service(s) by increasing the amount of knowledge required of the clients and forcing the duplication of logic.
I agree with AS’s pleasure at making the complexity explicit. It is this complexity which, when left implicit in a monolith, results in “the big ball of mud”.
I also think your views, Gene, on not exposing complexity outside the organisation, and instead providing coarse services, are valid and important. I think this should and will become a typical microservices pattern: fine-grained in our organisation, exposed as coarse-grained to others.
Of course, than then brings up the need to define the “organisation” where these boundaries are drawn. Is it a company, a department, a product division, a team? I think the truth is it should be contextual, and figure out where to draw these boundaries will be one of the ongoing organisational challenges of MSA.
LikeLiked by 1 person
An aggregation of microservices can be again a microservice – several simple-in-functionality single-responsible microservices make one complex-in-functionality single-responsible microservice. And such aggregations may be used inside as well.
For example, four lower layers in the first illustration of http://improving-bpm-systems.blogspot.ch/2011/07/enterprise-patterns-caps.html are microservices (see a code fragment in 2.2 at http://improving-bpm-systems.blogspot.ch/2014/08/bpm-for-software-architects-from.html ).
Possibly…the more services that are aggregated the more latency becomes an issue. Getting around the latency issue may push the aggregating service beyond the bounds of ‘micro’.
Two considerations about performance (including latency):
1. Prof. Donald Knuth once said “Premature optimisation is the root of all evil (or at
least most of it) in programming.” A typical sign of premature optimisation is extensive
discussion about performance issues during the design of a system.
2. Performance is “distributed” very non-equally over a software-intensive system – 5 % of code consumes 95 % of CPU
Thus let us have a clear design, implement it, run it, measure its performance, detect bottlenecks and optimise them.
LikeLiked by 1 person
It might seem presumptuous to argue with Knuth, but, he’s wrong when it comes to developing distributed applications. Ignoring the difference between in-process and out of process is bad enough, acting as though there’s no difference between in-process and over the wire is a foolproof method for building performance nightmares.
CPU utilization is the least of your worries with MSAs. Network latency, both that inherent in communicating over the wire and that due to traffic conditions, is the issue.
See the first paragraph for why it’s a bad idea to design without taking the network into account. Once you’ve detected the bottleneck, you’re optimizing by ripping everything out and re-doing it to account for issues that were obvious before you started.
LikeLiked by 1 person
Pingback: Wait, did I just say Knuth was wrong? | Form Follows Function
Pingback: Microservice Architectures aren’t for Everyone | Form Follows Function
I’m fairly new to programming – after feeling comfortable with npm / docker – i accidently created a micro-service architecture and lost control of the entire application (i’m the only dev on the team). The way I see it – micro services (MS’s) have an appeal that seems objectively correct, while the argument against MS’s seems flaky and abstract. I’m saying this in the face of an application so complex that I can’t grasp it… with 20-40 services, nowhere near 600!!!
But, the worlds made of atoms. I’d rather build a system of systems of systems than a monolith. Our short-term memory has limitations – we can only handle so many constructs at any given time. With that being said, I’d choose to use a monolith built out of microservices – (or a monolith of monoliths built of out microservices of microservices) – because that JUST makes SENSE – in my my mind. It’s like Ikea furniture.
My bias is to design in such a way that I have the option but not the obligation to distribute the application. Everything involves trade-offs, so leaning too far to either extreme will likely tilt you beyond the point where the benefits are worth the costs.
Pingback: Are Microservices the Next Big Thing? | Form Follows Function
Pingback: Microservices – Sharpening the Focus | Form Follows Function
Breaking up monoliths into granular services only to bring them back together again to construct the functional whole…is easier said than done. That’s the reason ESBs became popular with SOA, and even those had issues with service reuse and granularity, and we aren’t even talking more than tens of services in some cases. The complexity introduced by trying to create composite apps based on tens/hundreds of microservices – as proved by the various complex network models from Netflix, Twitter and Gilt – will only give rise to more frameworks to replace the ESB, and more governance practices to effectively govern and use them. These are the major items that microservices set out to eliminate and some of the major items stated as differentiators with SOA (dump pipes/smart endpoints), so we should see some interesting times ahead as ESB vendors will now start to claim this space as well (“atoms”, “snaps”–>microservices anyone)?
“…so we should see some interesting times ahead…”
Pingback: Microservices or Monoliths – Fences and Neighbors | Form Follows Function