Comment by zeendo

1 year ago

Surely one can imagine a middle ground between one giant monolith and a huge mess of microservices?

In some ways its more about organization of humans doing the work. Breaking some piece of a monolith off into its own application, not micro-service, has advantages that you avoid having to deal more than a 2 pizza team size on an app. Sometimes the business grows and you go from startup idea one-app-does-everything implementations into needing more de-coupled, single business responsibility organizations of code.

I suppose places like Spotify or Github may have good practices around working on large monoliths but I would think that takes a lot of effort to get right and may have trade-offs.

  • This is correct.

    It was always more of a team organization solution than a system architectural solution. Leaning into it too much on the latter created a lot of complications for the former.

Totally, I think there's a lot of retroactive justification for what's familiar whether it be microservice or monolith. They both have advantages and disadvantages -- we're at a point where deploying and running either is available on most clouds.

That said, I think interesting possibilities exist where the two approaches are blended. I work for a cloud [1] that supports a concept of "services" grouped within an app each of those services is a web server that can be configured to sleep [2] under specific conditions -- effectively serverless but without the loss of shared memory and all the efficiencies of running a more traditional web server.

The grouping of services also provides a way to spin off parts of an application while keeping it within the same deployment process.

1. https://noop.dev

2. https://noop.dev/docs/sleepy-services/

Depends what you wanted from Microservices. If all you wanted was scale, then Rails ActiveJob solves that very effectively allowing you to scale your job-runners.

If you're looking for the "mindset" of microservices, where you store the data separately and impotently, then I believe Rails discourages that mindset.

  • I keep hearing this "microservices to allow scale", in which "scale" implies performance, as some counterargument against microservices.

    Honest question, who ever seriously proposed microservices to improve performance? It doesn't take a lot of thought to figure out that microservices have overhead that will always put it in a disadvantage over a monolith in this regard.

    The only "scale" that makes sense wrt microservices is that of the scale of teams, and manage-ability of the scale of features and codebase. They are primarily a solution to "too many people working in too many poorly bounded domains". But as a solution to performance problems? Is it really proposed as that?

    • This was seriously proposed by some. E.g. "scaling services independently"

      Scaling services independently is usually a recipe for outages where something is at the wrong scale. Sometimes you want to separate workloads that don't fit the request response model well because they take too long or use too much CPU or RAM, but you don't need micro services to get that benefit.

      I don't think anyone was claiming it would lower latency for typical requests except maybe indirectly through materializing views in event-driven architecture.

      I think the steel man has been about scaling teams, but the discourse was not limited to that.

      1 reply →

    • It was proposed in the sense that Ruby, or python, or whatever webserver language you used (Perl, php, even JavaScript) was slow, single core, synchronous, database blocked, or whatever else made it “unscalable” and you built this tiny service that only focuses on your core bottlenecks like an api call that only returns coordinates of your map position on things like aws lambda.

      Then for some reason some junior engineers thought that you could make everything an api call and you can make services in the most optimal language and glue them all together to have functional “scalable” apps.

      And thus the horrors of being a web dev in 2016+ began.

      Of course it didn’t help SPAs were encouraging backends to be decoupled from front ends and completely hidden in their implementation so the fact that “it was now possible” enticed backend devs to experiment with multiple api services.

      5 replies →

    • Scale in a sense where you can scale that one part of system independently when it is micro service.

      You still can run into situation where adding a network call is small overhead over the optimization available where it has its own datababase running on its own VM where you can add more resources just for that specific thing.

      Maybe you can rewrite that part in a language that fits use case better for only that service.

Modulith - you still program app usually as single repo project, but you take care about code level modularization so in any case you are able to simply extract separate (micro)service.

A modular monolith is distinct from a "plain" monolith. It's a good middle ground for most web services.

  • What's a "plain" monolith? Is a modular monolith "just a monolith except we don't suck at coding"?

    • Let's use MVC for the sake of argument. A regular monolith has lots of models, lots of controllers, and lots of views. A modular monolith has several collections of models/controllers/views, which might be tightly coupled internally, but the collections as a whole exposes much smaller APIs to each other. You cannot just reach into an implementation detail of distantly related functionality, even if this functionality is "public" in the programming language package visibility sense (i.e. users repository is visible to users controller).

      This is basically what's accomplished by publishing a Thrift/Proto/OpenAPI IDL from a collection of packages comprising a network service. The key insight is that the serialization and networking parts of this are superfluous, what you actually wanted was the visibility rules.

    • A modular monolith has a single executable which runs in different modes, typically depending on environment variables. So you can run three processes in the mode that handles web requests, five processes in the mode that processes events on a queue (e.g. Kafka), etc. Eight processes, running in two different modes, but it's all the same executable. That's the basic idea of a modular monolith.

      By "plain monolith" I meant just any kind of monolith.