1. 48
    1. 31

      I despair of trying to convince people that a sanely constructed monolith is enormously preferable to a distributed microservice architecture, especially at the start, and doubly so if the team is small (<6 or so).

      1. 22

        Quite so often I get the argument that splitting services is “cleaner so that one service does one job” and “it enforces clear boundaries”.

        Each time I keep reminding people that clear boundaries and doing one job can also be done inside your service by having well defined classes, interfaces, libraries etc… you don’t need to split the application to get a clean design.

        1. 11

          There are some good motivations for splitting a monolith into micro services:

          • You need to be able to deploy updates to different components independently. Note that you still need to test updates, so this matters only if the process restart time for your monolith is noticeable to customers.
          • You want to enforce the principle of least privilege. This is actually a good reason. Even if you are writing in a safe language, bugs in the language runtime may allow an attacker to leak secrets. Putting anything handling crypto keys into a separate service (at the very least) is probably a good idea.
          • Closely related to the pervious point, you need independent failure domains. If you have some safety- (or business-)critical part of your service and some complex part, splitting them makes it easier to ensure that the critical part remains live when the complex part experiences bugs or attacks.
          • You need to be able to split your service across multiple hardware nodes to achieve the scale that you need. This is much easier with explicit communication boundaries, but be aware that you are now building a distributed system and this is at least an order of magnitude harder. The first rule of building distributed systems is don’t build distributed systems unless you have to.

          As you say, in 90% of cases none of these reasons apply, and even where they do it may only be for a tiny part of the app. There’s also one other closely related reason that isn’t technical:

          • VC-backed microservice-hosting companies are much cheaper than hosting services for monoliths and so it’s cheaper to deploy to a subsidised platform than to one that has a sustainable business model, even when you bake in the cost of moving in a few years when they finish burning their funding.
          1. 7

            You need to be able to deploy updates to different components independently. Note that you still need to test updates, so this matters only if the process restart time for your monolith is noticeable to customers.

            Why? Why would that be different between a micro service and a monolith. I’ve seen many monolithic and non-monolithic architectures over the course of my career, built by various companies or myself. I don’t really see how this can possibly apply. Either you have a zero downtime deployment or you don’t.

            You want to enforce the principle of least privilege. This is actually a good reason. Even if you are writing in a safe language, bugs in the language runtime may allow an attacker to leak secrets. Putting anything handling crypto keys into a separate service (at the very least) is probably a good idea.

            That actually depends a bit. This argument is given more frequently than relevant. There’s many real world applications microservice architectures where that actually does matter. In reality whether a setup is infiltrated depends on bad code or bad setups and in that case they typically mean that you can wave goodby to all your secrets (as in things like user data, etc.). Also it’s not a given that different secrets in your application are all accessible. While this is a rare scenario it’s true though.

            Closely related to the pervious point, you need independent failure domains. If you have some safety- (or business-)critical part of your service and some complex part, splitting them makes it easier to ensure that the critical part remains live when the complex part experiences bugs or attacks.

            Yes, IF done correctly. And that’s really not a small if. One part still needs to interact with the other part. So it’s never completely split off. But then we could go into IF stuff is done correctly in the monolith it is the same. But I agree that in most companies/products/setups this is easier with microservices.

            VC-backed microservice-hosting companies are much cheaper than hosting services for monoliths and so it’s cheaper to deploy to a subsidised platform than to one that has a sustainable business model, even when you bake in the cost of moving in a few years when they finish burning their funding.

            This almost sounds like a joke to me. Do you actually mean that? Do you have any form of backing for that statement or do I maybe completely misunderstand what you are saying? Hosting a monolith is classically a lot easier and simpler to come by. Think of just renting a server/instance and deploying your Rails/Django/… monolith. Replicate is as much as you want/need and you are done. That’s usually orders of magnitude cheaper than anything even remotely related to microservice hosting. Even if there was magically zero overhead to pay for for service to service communication and the individual service overheads and the parts required for a sane microservice architecure, etc.

            And I mean a VCs goal is to make as much money as quickly as possible from a venture, so why would they even go for cheaper?

          2. 6

            You need to be able to deploy updates to different components independently. Note that you still need to test updates, so this matters only if the process restart time for your monolith is noticeable to customers.

            In my brief career working on a network service, we never restarted the server outright; rather, we would start up an instance of the new version and switch over seamlessly from the old. Then eventually take down the old one (leave it up for a while to allow switching back in case something goes wrong). Is this not standard procedure? It doesn’t seem like restart time matters given such a design.

            You want to enforce the principle of least privilege. This is actually a good reason. Even if you are writing in a safe language, bugs in the language runtime may allow an attacker to leak secrets.

            Sounds like an excellent argument in favour of capability safety. (As I recall, log4shell started a cottage industry of blog posts arguing for capability safety.) The issue of bugs in the language runtime is—not illegitimate, but very, very marginal, especially considering that the kernel (ie, runtime of unix, another capability-safe programming language) is as much of a bug vector, if not moreso.

            VC-backed microservice-hosting companies are much cheaper than hosting services for monoliths and so it’s cheaper to deploy to a subsidised platform than to one that has a sustainable business model

            lol

            1. 2

              In my brief career working on a network service, we never restarted the server outright; rather, we would start up an instance of the new version and switch over seamlessly from the old. Then eventually take down the old one (leave it up for a while to allow switching back in case something goes wrong). Is this not standard procedure? It doesn’t seem like restart time matters given such a design.

              I have implemented this a dozen times or so for almost two decades. Since the old days with Apache httpd and still to this day on aws, kis, gcp, etc. This process can be done in less than a second on a service with proper latency. I also don’t know what GP means with independently. If there is no downtime, there is no problem to begin with.

        2. 2

          Another thing to keep in mind here is that if you split into microservices, even though it’s usually very standard each of these services also does the whole microservice harness part. Which are thing that can go wrong differently in different services. Most of the time they don’t. But of course it’s silly to assume nothing ever goes wrong. And these things can be very hard to debug.

          Each bit of thing you add is a thing that can go wrong. So you can essentially prevent whole classes of bugs and a lot of complexity in debugging.

          And of course that comes on top of all these parts having upgrade, migration paths, bugs on their own, etc. So the potential for issues increases on all of these fronts.

          People like to talk about credits for trying new technologies, but tend to forget about such things when it comes to more moving part, whether in-house or external.

          It’s particularly funny when the same person that argues for micro services (and usually a whole slur of technologies with it) to make things easier somehow is worried when you use a different (well-established) programming language everyone on the team is familiar with.

          I think a lot of that comes from (the assumption that) “everyone is doing this”. I also think that since a lot of these technologies are tied to companies and products there is a huge amount of marketing, which has an effect on developers/teams/companies.

          And there’s just so many ways people profit from the whole microservice hype. SREs earn more than SysAdmins, Google, Microsoft, Amazon, RedHat, Grafana, Hashicorp, etc. all have products for microservice architectures and make more money if you have more services, people write books, make premium videos for topics around microservice architectures, consultants (like me) make more money when dealing with such topics.

          So of course the overarching theme is “use microservices!”. Also that has been going on for long enough that there’s people who expect that and don’t know any different.

          This isn’t some conspiracy, the is the usual pattern with monetizing hypes. And unlike “blockchains for everything” it’s not like this doesn’t also work. Whether code is part of a monolith or a microservice on the functionality side of things not much changes. I also don’t think that microservices are significantly worse or always a bad idea. There is just an unfounded default assumption that they are the best way to go pretty much always. And people - if they are there long enough - sometimes realize that. Sometimes not, because the main reason to switch from a monolith is that it’s some bad old code which nobody really understands that will be rewritten in the process.

          So while it’s all done under the “migrating to microservices” umbrella what really happens is the code simply is turned into something sane, maintainable, which is exactly “clean interfaces”. Sometimes you also have things like weird ways of keeping state that essentially have to go away if you move to microservices. Yet another part is that you probably have understood your problem space enough to simply write a good service, with good abstractions, etc. Many success stories work like that. You did something X years ago and have worked on it since, now you have to change everything, likely rewrite a lot of things. Likely the outcome will better than you could have done all those years ago. And as an added benefit you can now say how you have skills with such a thing and of course everything will be better, cause you had a hand in it.

          So lots of psychology kicks in there. But a lot of this is true for most new things. For example a new programming language. If you write something in a new programing language, likely something you have experience you have a new clean project with all the learnings and zero of the baggage/technical debt and often fewer or no compatibility requirements. So other than not knowing the language well you actually are in a better situation than before. And if you have some experience and the language is kinda similar (which really is the most common theme) a new language won’t be much of a hindrance. And everything that is is easily blamed on simply not knowing it well enough yet.

      2. 4

        The words “sanely constructed” are doing a ton of unexamined work in your comment. Perhaps there are people who can manage and scale up monolithic codebases from a small start to dozens or hundreds of developers and vast amounts of code and functionality, and who can do so in a way that stays architecturally clean and maintains clear separation of concerns and so on.

        But I’ve never personally seen anyone pull it off. Instead the monolith always becomes a hairball of cross-cutting concerns and lack of clear functional boundaries and other hacks, and eventually someone decides it would be easier to just acknowledge the inevitability of Conway’s Law and start splitting the thing up by team.

        1. 4

          Perhaps there are people who can manage and scale up monolithic codebases from a small start to dozens or hundreds of developers and vast amounts of code and functionality, […]

          The vast majority of systems never need to reach that scale. Of course, if you are completely certain ahead of time that you can’t be successful with anything less, go nuts, but for every system where microservices were justified from the start I expect there are hundreds where it wasn’t.

          1. 1

            The vast majority of systems never need to reach that scale

            Well, the vast majority of programming projects fail quickly, which doesn’t really make your point for you. But of the ones that stick around long enough to go from, say, 5 developers to 50, I think you’re going to find a lot more painful stories where they decide that they need to start breaking things up due to the difficulty of getting that many people to continue working in a 100% architecturally perfect manner.

            So like I said: the word “sanely constructed” are doing a ton of unexamined work in your comment. You might as well just advise people not to write code with bugs in.

      3. 3

        Our experience is mixed but I’d say a Lambda/SQS/CDK based architecture has a relatively gentle on-ramp compared to what people generally understand to be a container based micro-service architecture.

        The amount of time teams have to be in each others’ business for all kinds of things with a monolith should not be underestimated and I don’t think is worth it from 4-5 product teams onward.

        1. 1

          Lambdas start as simple functions that accrete functionality over time. Not only do they become expensive but also they are pretty hard to migrate without a full-scale rewrite in many cases.

          1. 1

            Haven’t seen them become expensive yet and there’s a nice converter library to turn our lambdas into express apps if we need to move to containers sometime in the future.

    2. 16

      Would it kill Dan to put a date on his site?

      1. 5

        The archive page / main page lists this article’s date as April 2023.

        But I, too, expect to find the dates on article pages themselves.

        1. 3

          Correction: that page lists this article’s date as “04/22”, meaning April 2022.

    3. 7

      Sorry, but defending a simple architecture and GraphQL and Kubernetes in the same article is nonsense

    4. 3

      we use Kubernetes because knew that, if the business was successful (which it has been) and we kept expanding, we’d eventually expand to countries that require us to operate our services in country.

      I’m not sure what kubernetes has to do with this requirement. A docker container I understand; you can deploy the thing basically anywhere, and it’s a monolith, so one container I guess? How is kubernetes any help here at all?

    5. [Comment removed by author]

    6. 1

      Python no framework, does this mean the entire thing is a Flask app or something?

      1. 4

        No idea, but Python has WSGI + ASGI and you do not really need that much on top to get the job done.

        I sometimes find it hard to do serious work in Django simply because it doesn’t compose.