Why I'm No Longer Talking to Architects About Microservices
blog.container-solutions.com
blog.container-solutions.com
Over time, I've found that the only reliable way to reason about engineering decisions is to work backward from the business use case. What are we trying to accomplish? What's the time frame? What risks are worth taking now vs later? Everything else...patterns, paradigms, "best practices"...only make sense in that context. The rest is academic, and often divorced from reality tbh.
Also noticed that many strong opinions in engineering come from people trying to avoid pain they've experienced before. But the solution that saved them in one situation can easily become a liability in another. Patterns ossify into rules. That's why I try to keep my reasoning grounded in outcomes and context, not ideology. Most "best practices" are just local maxima..useful until they arent.
Code monkey is really the more accurate term. Not even slightly kidding here.
Who are they? People that advocate for specific patterns or argue about meanings of terms used?
The main difference is that most people working in electrical or electronic engineering aren't being forced to ship half-working products that might change tomorrow. When we ship a product, it's "done". The cost of modifying it later is not zero. Well, the same is true for software, but this is a reality that business gaslights developers into ignoring.
Updates are fine. Forgetting quality because of the possibility of updating is not.
And given that finite element analysis has flaws, one wonders what will replace it and when.
I am the one who knocks, and I’m not sure where we’re all getting the idea that society desires ethical, competent, software engineers.
The latter seems to occur and mature in software more.
I started down the path in mechanical but didn’t stay in that track long enough to get one.
Personally I think software engineering is absolutely engineering, it just has mostly different constraints from physical engineering. Most of this has to do with the dealing with the costs and consequences of building things in the physical world. Without those disciplines, a huge capital cost goes into building a bridge that fails, or an expensive machine that can't do its job. We also have to account for the limitations of physical materials and a harsh environment, which are in some ways harder to account for, but also more stable as a well-understood substrate than pure software (ie. all animals have some intuition about physical things, physics doesn't change, materials capabilities change slowly, etc).
When folks lament the lack of "discipline" in software engineering I think it's a misplaced, grass-is-greener sentiment that hasn't really been thought through. The reality is software has different constraints, not harder or easier, just completely different apples to oranges differences. For instance, durability and maintenance in physical objects is about material properties and physical wear and degradation from the operating environment, whereas software bits are infinitely durable and replicable, but they get broken by the environment itself since they have to interact with thousands or millions of other software artifacts created over many decades. With physical engineering it's mostly about discrete objects with natural and intuitive encapsulation that are in a sense "immutable". Some software is like this (like pre-internet console video games shipped on cartridges), but typical cloud-based software is nothing like this, it's a constantly evolving tangle of interconnected logic and ever-growing data used for widely heterogenous purposes, often never fully understood by any one person or entity.
This messiness is one of the frustrating things about software, but it's also its strength. Anyone that tries to declare rigid civil-engineering-style discipline to software will not survive in the marketplace because most software is not life-or-death. The discipline put into the Mars Rover or the Therac 25 successor would simply be overkill for average software. That said, of course there are cases where the importance and impact of software correctness is unknown, like if the government were to start using social media sentiment to impose real-world consequences on its citizens, but these types of considerations are much more fluid and harder to nail down than physical properties like "will this bridge stand up for 50 years". Software engineering in my view, is about leveraging the malleability of software to solve problems in a constantly evolving landscape. We're not just standing on the shoulders of giants, we are directly calling their APIs to solve new problems they couldn't even have conceived of. One could argue this is too broad to really be "engineering", but I can't think of a better word to describe the highly technical process of understanding and solving problems with software.
Anyway, it's not really so surprising that there are few hard and fast and replicable rules in "software engineering" as there really aren't in, say, essay writing. There are best practices and tips and techniques that are generally more effective than others. And there _are_ actual constraints around software that don't exist around essay writing as, ultimately, software does have to translate to real physical limitations like available memory and such, but the abstraction away from those physical limits is by and large the point and purpose of software.
All patterns & practices come with their benefit and drawbacks. So all decisions are very much dependent on the circumstances. This is what you called "local maxima".
Add to that the bias for the new dev/leader to push some change to show impact - you get a regular pendulum swing between extremes.
One problem underlying it all is stable engineering leadership. This itself is a challenging balance between stability avoiding dumb architectural churn like I describe vs ensuring you have some new blood to inspire fresh ideas. Another problem is just misatribution: we see X problem in the product, some eng pushes Y big solution to X even though there’s probably a simpler path to solving X in the current stack. Often you don’t really need to do that big revamp but to show impact? devs preference? we do X anyway.
The older I get the more I feel like this is a feature, not a bug. I have spent too much time over engineering systems that end up being canned because leadership decides to go in a different direction. These days I am much more concerned with striking a balance between perfect and good enough.
Get something out into production, start generating some revenue and finding the stuff people like about it, then see what is giving you the most problems and fix that. That’s going to be a much more successful path than never shipping anything because of endless polishing and optimizing.
If I ever find myself spending a long time debating some technical decision (aka bike shedding), I have learned to hit pause and say let’s just pick a path and go with it. As an aside this also works for deciding what restaurant to go to or what kind of pizza to order.
If you feel you need micro-services to force an organizational change, don't equivocate, just lead with that, and get back to business.
It's also harder to assign blame for performance issues when your teams write libraries. In microservice, your team can isolate exactly how much CPU usage your code takes. But few companies can isolate the performance cost of a library. When your main service goes down, it's tricky to assign the responsibility to a single team to fix.
Finally, microservices give you ironclad control over your API surface, while in many companies other teams can often call into any part of your library. As other teams grow tendrils into your team's code, your support burden grows and you have to keep supporting unintended parts of your API.
Now all of these are fixable, and I think we should fix them. Writing and using libraries is easier and lower overhead than putting network calls everywhere. But until you fix the above issues, companies will keep sliding into microservices.
I think he's right - microservices are very often used in situations where a library is clearly the right tool for the job. In my experience the main reasons people don't use libraries are: a) the people in charge of the place where you should put the library are too territorial, so it becomes easier overall to start an entirely new project and deal with the very large downsides of microservices, and b) they want to use a different language, and disappointingly FFI over HTTP is usually easier than "true" FFI.
Think: how much overhead, one function has in terms of the CPU calling it, then returning it.
How many 1000s of X more are you adding by making that a function inside another webserver.
Yes, there are times when a microservice is correct, there are many-many-many other times where using them is pure waste.
The organizational costs come from communication overhead between engineers: Sync or maybe async calls within a codebase turn into an ad hoc distributed system, where a different team (and maybe different management chain) owns each network endpoint.
When each team is responsible for one microservice, they can manage that with much less painful coordination with other teams.
I would do micro services only once the requirements are very stable and there is a clear need for scalability. Microservice first architecture is a recipe for complexity.
One difference/advantage in a monolith is that you don't have to worry which version the other microservices are on.
If you have no other choice because you’re a tiny startup, then fine, but at least show the DB the respect it deserves, and read its documentation. You wouldn’t (I hope) write and run code when you had no idea how it worked, or what the potential ramifications were, so don’t do it for the rest of your tools.
And as you correctly point out, the odds are low that there’s any semblance of a centralized configuration (nor that anyone knows what all the options for). So you wind up with 30 different DBs, all with different performance characteristics, and a ton of data duplication. Not to mention the observability nightmare. You want to trace something E2E? Have fun following all the traces and queries.
In the end I think that microservices are not a big deal. It’s like choosing your programming language or choosing whether you want to use object-oriented programming. These decisions all have impact, but they generally aren’t revolutionary decisions. Object-oriented programming didn’t give us a massive wave of reusable code. Rust hasn’t unlocked some new, previously unseen level of developer productivity. Microservices are the same way.
> seem very confusing to grug
This is the only valid definition. If you don't have separate data stores, you don't have a microservice. You have a mess that will break.
> Problem Three: Microservices Without Organizational Change Is Pointless
Also 100% correct. Microservices only work if the only necessary coordination between teams is an API. If you have to coordinate deployments or other work with another team, you've broken the model.
Now, that's not to say that you can't help another team add an API call to their service to make your own service easier to run. Or that you can't coordinate feature development across teams.
But at the end of the day, each team needs to be able to deploy or roll back independently of what any other team is doing. It needs to work as if every team is another company who they can only loosely coordinate with (hence the term loosely coupled).
OP is certainly right here, microservices are a means to an end, not an end.
From an electrical engineering background, it is mind-boggling to me how we got to this convoluted software world. It’s like having different electric sockets in the same building. The only hard standards seem to be IP and HTTP.
I just have two basic explanations for that: 1. Most software today has no relationship to physics or the hardware it is running on. Hence, there is no need for optimization. 2. In new projects you always start from scratch and there are few guidelines/truths/principles to hold the developer accountable to. And if there are, then you can always discuss their applicability to your problem.
The reason things shift for software is because they can and because there's no 1 "right" solution to almost any problem. There's no 1 correct way to represent data. And when we've tried to do that in the past (see SOAP) it ends up in a wild spaghetti mess of standards that tend to hamper development rather than speed it up.
There's also the very real problem that users of software LOVE to work around standards to the point where they create their own standards that ultimately end up needing to be supported in software. I can't tell you the number of times a "description" field in some set of data has ultimately ended up needing special handling in our data normalization process because an end user has decided "When I mark foo with this, it's actually a bar and the system needs to handle it slightly differently". To which our POs are happy to oblige. Often because software we didn't write is what the users are interacting with to send us data and the "description" field is the only thing they have the power to change.
Too true.
In my experience, micro-services were always proposed by either ivory-tower folks chasing the latest fad, or by more practical folks who really wanted to drive an organizational change - a means to an end. The big issue, and friction, occurs when the first group, pushing the notion, didn't recognize that an organizational reconfiguration is necessary for success.
In my experience there's plenty of blame to lay here. Some organizations are too siloed and some architects are too inexperienced.
The following aren't inherent to microservices, but are general architecture concerns: scaling up to handle more concurrent requests, hitting your SLA uptime, reducing defects or memory usage by avoiding statefulness, reducing latency, separation of concerns to improve maintainability, etc.
Are these not immediately obvious impacts to the business? Is it not obvious how microservices can help here even if it's not the only way to solve these?
My main question is whether the author is as similarly inexperienced as the architects.
> Are these not immediately obvious impacts to the business?
Depends; for b2b loads all those concerns but the final one can be be met with a single beefy server for DB writes, with multiple read only replicas.
Run multiple instances of your monolith app behind a load balancer and you should be good for maybe 100k users working on that app at mostly the same time.
With care (redis serving session data) this is fine for even very high loads.
Once you start doing b2c and have millions of users logged in and doing stuff at the same time then those concerns are valid.
The truth is that micro services are a tool. However your organization has broadly agreed to utilize the tool is the correct approach.
At very least, having clear boundaries on data ownership is something I really wish my company had done from the start. We have legacy structures that are very hard to iterate on because they get loaded by ~20 different applications directly from the database. That means any minor change to that structure requires careful planning and roll out of the shared library to these 20 services.
Were these behind a service, we'd still have to negotiate the structure (we could, for example, delete a field willy nilly) but we'd be able to add new fields to the structure or change the way those fields are populated to meet current business requirements without a mass rollout.
I do think the micro/nano approach can often be wrong. I think a service should be as big as it should be to cover the domain it's dealing with. But, importantly, who owns what bit of information is by large the most important thing to get right.
I see what you are getting at though.
It can be hard to determine when something should be a service or library and I don't know if I have a clear answer either.
We also have, for example, libraries that purely compute data. However, they have to be consistent across the system and it would actually be pretty helpful if they were a microservice instead as the computations often need to be changed or updated.
Perhaps when it's business logic it should be a service?
I definitely see the need for libraries like compression, IO help, or even just pure math like doing matrix multiplication where older ways to compute aren't necessarily incorrect.
At least that's what I believe, so that's how I read it.
At a bare minimum, if there's some sort of mutable data involved then I think there should be a single service that owns it. But I could also see reasons to create services which don't involve mutable data.
It does somewhat come down to complexity though. Like, for example, I think a "matrix multiplier" service would be silly. Or even just a general "do-math" service. But a service that, for example, takes in raw video and spits out compressed video? Now we are talking about something that probably is better as a service and not a library as you likely want to do things like control encoding values and standards system wide.
Just a little about my background. The systems I worked on, for example, shared user information using the `user-lib` library which contained all the details of how to fetch (and insert, and update) a user from the users table. Many services used that library to pull user information which has been a mess to untangle.
I also have a working definition of a microservice, which is that it is a functional part of a system which exposes its functionality to other parts of the system via HTTP. This works for my team.
In general, we shouldn’t fetishize any particular technology, idea, or phrase. If a term obfuscates more than it clarifies, it’s not very useful.
In my definition, what matters is there’s something responding to HTTP requests internal to the system.
How do you differentiate service and microservice?
I don't know why people get satisfaction from writing the same posts for a decade about microservices but can we move on at this point? We know that microservices are better for development at larger organizations but it comes with a cost at things like service fragility, service discovery and investment in things like observability and alerts, etc. This is well established at this point, so if you want to write a post that talks about this, please don't.
As long as there is monorepo, and anything in the testing boundary could be built and edited together that is fine for me.
I personally don't believe at all in microservices, at least not in the organizational sens, I do not mind e.g. genservers in Erlang but then teams owns many of them. But that said this trend is not proof that they are bad, just that they do not magically solve the problems.
I could watch it happen in real time. Person A would advocate a position on one of those items, and their nemesis on the team, B, would then build their whole personality around being against that position. They would adjust every existing belief to now fit their new perspective. It would become boringly predictable.
So when someone is really passionate and certain about something like this, my natural thought is "who hurt you?". Especially on something as amorphous and hard to pin down like microservices where it's easy to attack it from a hundred angles that likely have no relevance to an actual implementation.
Like, it really doesn't matter that much. You can make an excellent solution using almost any approach. You can use all sorts of frameworks and languages and platforms, etc. It'll all be okay.
I remember one guy screaming at me because I didn't use the pattern he wanted in a certain project. I didn't really care, but later I found he had a fight with the CTO the day before about said pattern.
> Like, it really doesn't matter that much. You can make an excellent solution using almost any approach
Yep. One can also make a horrible solution with almost any approach. ;)
That sentence is doing a lot of heavy lifting.