5 ms·
No, they aren't. The entire point of the big ball of mud is that there are no meaningful divisions in the code. Everything uses everything willy-nilly, at the s
by jerf 4y ago
No, they aren't. The entire point of the big ball of mud is that there are no meaningful divisions in the code. Everything uses everything willy-nilly, at the smallest possible level of abstraction. There is, metaphorically if not always entirely literally, not a single line of code in the system that you can change without fear of bringing something else down that you may not have even known they existed.
Microservices are not a miracle cure or the solution to every problem, but they do force divisions within the code base. Every microservice defines an interface for its input and its output. It may be the sloppiest, crappiest definition every, with dynamic types and ill-defined APIs and bizarre side effects, but it is some sort of definition, and that means if necessary, the entire microservice could be entirely replaced with some new chunk of code without affecting the rest of the system, cleanly cut along the API lines. This microservice may sloppily call dozens of others, but that can be seen and replicated. It may be called by a sloppy combination of other services, but the incoming API could be replicated.
However bad the architecture of the microservice may be, however bad the overall architecture of the microservice-based system as a whole may be, this will be true by structural necessity. The network layer defines some sort of module.
They can create big balls of spaghetti, certainly. They can in total create a big mess; they are not magical architectural magic by any means. While a full replacement of a given microservice is practical and possible, if the boundaries are not drawn correctly to start with, fixing that can be much harder in a microservice architecture (with corresponding separation of teams) than a monolith.
But they fail to create the situation that is what I would consider the distinguishing characteristic of a "Big Ball of Mud", where there are no partitions between anything at all. Big Balls of Mud have no equivalent of "replace this microservice". Microservices by necessity, to be "microservices", have partitions.
- jasonhansel 4y ago> if the boundaries are not drawn correctly to start with, fixing that can be much harder in a microservice architecture (with corresponding separation of teams) than a monolith. Therein lies the problem. Nobody draws these boundaries correctly on the first try, and the correct boundaries can shift rapidly over time as new features are added or requirements change.
- nprateem 4y agoThe main reason is to stop crap developers using globals all over the place, or passing around hash maps stuffed full of config that aren't clearly defined in one place just continually mutated (and similar bad issues). Still, crap devs will just find their own ways to mess up with microservices, but at least they limit the blast radius.
- HardlyCurious 4y agoThey limit the blast radius to the scope of systems that either directly or indirectly call the microservice, which is commonly the same blast radius as a monolith that was replaced by the microservices.
- esailija 4y ago> It may be the sloppiest, crappiest definition every, with dynamic types Funny you said that since a microservice API is always dynamically typed and its usage cannot be checked by compiler. And the more microservices you use the more dynamically typed the whole project gets overall. While you can opt into a free for all everything importing everything, all languages do also support creating modules which define APIs for consumer and maintain compile time type checking.
- okamiueru 4y agoAlthough true to some extent, this is also a tooling issue. We use OpenAPI and generate clients. Strictly speaking the interoperability layer doesn't know the truth on the other side, but when generated correctly, the developer doesn't need to worry about it.
- esailija 4y agoWhen you change function signature it doesn't compile until you fix all the call sites. Maybe after you see all the broken call sites you think that's too much work maybe there is some other way to do what I want. When you change anything about an endpoint, it compiles just fine no matter what clients there are or what they are doing. You proceed with the change without worry. Yes, you can have some self-discipline to also generate the open api documents, generate the clients and then check all clients but self-discipline like that is not reliable. So while tooling can help it's still not the same thing.
- com2kid 4y ago> When you change function signature it doesn't compile until you fix all the call sites. Maybe after you see all the broken call sites you think that's too much work maybe there is some other way to do what I want. Improperly versioned dynamic libraries want a word with you! Perfectly possible to foot gun yourself with compiled code and broken API boundaries. > When you change anything about an endpoint, it compiles just fine no matter what clients there are or what they are doing. If I am exporting a DLL, same thing happens. Working on a true monolith, the entire app is compiled as one giant executable, sure, then I get compile errors.
- naasking 4y ago> No, they aren't. The entire point of the big ball of mud is that there are no meaningful divisions in the code. Everything uses everything willy-nilly, at the smallest possible level of abstraction. There is, metaphorically if not always entirely literally, not a single line of code in the system that you can change without fear of bringing something else down that you may not have even known they existed. This is bit of a strawman. The equivalent strawman criticism for microservices is that every function runs in its own networked service. Is that truly representative of the reality? Of course not, and neither is your breakdown of big ball of mud. I think this is a fair analysis of the BBOM: http://www.laputan.org/mud/mud.html http://www.laputan.org/mud/mud.html
- jerf 4y agoFunny, I was thinking of linking to that page myself in support and decided against it. I particularly was thinking of: "What does this muddy code look like to the programmers in the trenches who must confront it? Data structures may be haphazardly constructed, or even next to non-existent. Everything talks to everything else. Every shred of important state data may be global. There are those who might construe this as a sort of blackboard approach [Buschmann 1996], but it more closely resembles a grab bag of undifferentiated state. Where state information is compartmentalized, it may be passed promiscuously about though Byzantine back channels that circumvent the system's original structure." and "Such code can become a personal fiefdom, since the author care barely understand it anymore, and no one else can come close. Once simple repairs become all day affairs, as the code turns to mud. It becomes increasingly difficult for management to tell how long such repairs ought to take. Simple objectives turn into trench warfare. Everyone becomes resigned to a turgid pace. Some even come to prefer it, hiding in their cozy foxholes, and making their two line-per-day repairs." Superficially it may seem like these criticisms apply, but they don't. Microservice architectures can't have big global variables typing things together, structurally. Even if "everything talks to everything" (which is actually unlikely, sarcasm aside, even the absolute worst systems have more structure than that in a microservice architecture), it does it through a defined mechanism of RPC. State can't be passed through "back channels" because no back channels exist; you must go over the network, which is the "front" channel, not a back channel. By structural necessity, a microservice confines the scope of changes in the microservice code itself. There are then of course still scopes of changes that are even harder with microservices at the global level, but for refactorings that aren't behavior changes a microservice necessarily confines the scope of changes to the microservice itself, a small fraction of the whole. As long as the API accepts the same input and returns the same output, it can not blow up another service three layers away because it has no access. But that's a distinguishing characteristic of a Big Ball of Mud. Big Ball of Mud isn't just a slur; it's a distinct pattern as described in that paper. At best a microservice architecture can be a lot of smaller "balls of mud" hooked together, and that's still a problem, but it is its own problem. This is proved by the fact that the solution to a Big Ball of Mud won't work for an microservices architecture disaster... indeed, they aren't even sensible. If two problems require separate solutions and the solution to one is not even conceivably applicable to the other (that is, not even a "bad" solution but simply no solution at all), they are clearly not the same problem.
- dagss 4y agoOk, so if this is where you come from: "The entire point of the big ball of mud is that there are no meaningful divisions in the code.... Everything uses everything willy-nilly....not a single line of code in the system that you can change without fear of bringing something else down that you may not have even known they existed" ...then OK, perhaps the developers who caused the state you describe above would not cause the exact same problems with microservices -- but will they really move fast any not cause a mess given ANY kind of environment? The state you describe is not normal of monoliths by any stretch. It may be normal of old legacy systems with 5 generations of programmers on it. Also I believe microservices will have other kind of problems, but still deep problems, after 5 generations of programmers. If preventing people from running in the completely wrong direction of the goal is your main concern -- why even be in the race at that point. Find new people to work with. If you personally had success rewriting a Ball of Mud into microservices, consider if perhaps the "rewrite" is the important word (as well as quality of developers involved), not whetyer the refactor was to a new monolith or new microservices. Microservices with boundaries drawn wrong can cause you to need to spend 20 programmers do the job of 1 programmer. Perhaps the mud looks different from a Big Ball, but it is still mud.
- drewcoo 4y ago> Microservices are not a miracle cure or the solution to every problem, but they do force divisions within the code base. Do they? The code itself may be in entirely separate repos but still be tightly coupled. Monoliths can have cleanly separated libraries/modules, those modules built from separate repos or at the very least, different namespaces. The "macroservices" I've been seeing are many separate containers all sharing at least one data store. So they have all of the disadvantage of the "ball of mud" monolith combined with all of the disadvantage of much more complicated infrastructure. Yet the people working on them think they're "doing microservices" because k8! The microservice separation is not just code in separate repos. It's also everything else behind the kimono - keep that kimono clasped tightly!