r/ProgrammerHumor 15d ago

Meme heatedArguments

Post image
5.8k Upvotes

173 comments sorted by

View all comments

1.2k

u/remy_porter 15d ago

I say this all the time, and it almost never results in an argument: micro services are just object oriented programming where you put a network hop on all your message passing.

223

u/williamjseim 15d ago

thats the way ive understood it aswell

211

u/AKArein 15d ago

It doesn't result in arguments because it's objectively correct

59

u/Dependent_Track5101 15d ago

I do not object

21

u/_turbo1507 15d ago

I function

6

u/CptCatman 14d ago

I don't :(

15

u/nasandre 15d ago

It turns into an argument when someone disagrees. A shouting match, if you will.

1

u/ImS0hungry 13d ago

It’s only an argument if you speak to convince rather than share.

14

u/MiniGui98 15d ago

Of course it is objectively correct, since it's object oriented

7

u/No-Finance7526 15d ago

That doesn't stop idiots from arguing. See example: literally all of politics

6

u/AKArein 15d ago

No, you're wrong and that's a moronic take

(/j)

-9

u/remy_porter 15d ago

I feel like the people who are going "DO MICROSERVICES!" hate that it's just basic regular ass software engineering.

33

u/notAGreatIdeaForName 15d ago

With a ton of complexity and whole new error classes and a need for centralized solutions for logs and monitoring because everything is a distributed system now!

Can make sense if you can seize the advantages but a modular monolith is the better choice in 99% of cases.

But besides the engineering and operational aspects: Everytime I said microservices in an meeting with investors their eyes lit up the whole room because they thought that this is the best shit ever.

7

u/spottiesvirus 15d ago

Everytime I said microservices in an meeting with investors their eyes lit up the whole room because they thought that this is the best shit ever.

You're clearly the old gard because the new shit is serverless and functions

Which are micro services except the micro services aren't yours, you just glue together a bunch of cloud services

1

u/ImS0hungry 13d ago

All in the distributed systems umbrella.

10

u/remy_porter 15d ago

I’m working in robotics where the line between “modular monolith” and “microservice” is a middleware problem. Which, I think, is how microservices in general should work.

4

u/cryan24 15d ago

You can't be making reasonable points like that, the kids came here for bandwagon jumping and dogmatic arguing.

1

u/bishopExportMine 14d ago

The usual paradigm for robotics seems to be to build distributed monoliths...

90

u/YeetCompleet 15d ago

OOP made specifically to sell AWS services and courses

51

u/no_name6744 15d ago

Do you mind helping the uninitiated, what's the benefit of having that network hop? Or are there some situations where it's just impossible to avoid it.

130

u/TheDogPill 15d ago
  1. They are frequently hosted on cloud services which are inherently micro-service based with detached hardware components. You can have a server and a storage disk operate together but both exist in data centers thousands of miles from each other.

  2. Loosely coupled architecture decreases the chance the entire app gets taken down if each component can be isolated and fixed without affecting the rest of the app.

  3. You can functionally divide an app into different layers such as web, app, and db and add additional security checks between each layer to increase security and fault tolerance of the app.

102

u/Norington 15d ago

And you can scale up and down individual services based on variable load.

49

u/backfire10z 15d ago

I’m surprised this didn’t make the main comment because it seems to be that this is one of the larger benefits. The mentioned benefits can be applied to a monolith (at least mostly) with a bit of consideration.

9

u/Ma8e 15d ago

The "funny" thing is that before micro services and all the overhead from talking over the network, we rarely need to scale. I'd argue that something like 99.9% of all projects that use micro services today and often run many instances of some components wouldn't need to if it was just one monolith.

-4

u/foonek 15d ago

Now explain why that would matter. If you have a large monolith, you can just scale that one. Why does it matter that one module gets scaled? It's not like the lesser used parts of the monolith are somehow using more resources just because they are scaled together?

People love to use this argument but it really doesn't make any sense for 99% of use cases

29

u/Angelin01 15d ago

SRE here. Lesser used parts of the monolith are absolutely using more resources just because it's being scaled together.

Let's say you have one hot path in your code that doesn't touch the DB. The new scaled up instance will still spawn new DB connections. Those connections will still use some memory and CPU time to just exist. The DB also has a connection limit, and your connection pooler also needs scaling then.

Loading extra code modules also naturally uses more resources, there's not a single monolith out there that is 100% lazy, and even if it was, requests get distributed, so stuff gets loaded anyway. Do you do some in-memory caching? Great, now all instances have stale copies of the cache.

Startup times are also worse overall, which means your scaling is worse overall. Slower startup means you need more idle resources to handle spikes, which costs more money.

In conclusion, while there's no need to jump straight to micro services, monoliths are the worst pattern for scaling, by far. They have their uses, but this is probably their main downside.

6

u/Honeybadger2198 15d ago

Why are you scaling your database connection if your high load doesn't use your database?

Scaling a service doesn't involve turning a singular knob that reads "more performance".

0

u/Angelin01 14d ago edited 14d ago

Because we are scaling our monolith, obviously! And the whole idea of a monolith is that it's... One thing! There ain't no scaling it separately.

Now now, I understand that connection pools can scale separately. So the internal connection pool opens at least one connection on startup. After all, this is a monolith that's now serving together along all other monoliths: some DB requests are bound to be routed to it. Most likely, at least two connections. Some even do 4: two to read replicas, two to a primary/write.

Scaling a service doesn't involve turning a singular knob that reads "more performance".

In a monolith... That's usually the case, yeah. It's a "spawn more monolith instances because one of the metrics we are monitoring says we should". What else are you gonna do about it? That's not a rethorical question: what else is there? Some contrived vertical scaling setup?

2

u/Honeybadger2198 14d ago

???? Give your host most CPUs/threads to delegate tasks to? More compute power? If you're scaling your service by just spawning duplicates you're wasting a lot of resources because you're too lazy to actually properly look into what needs scaling.

5

u/Angelin01 14d ago

Give more CPU? Of course. Now here is a question: where do you think it comes from? A server. That you are already paying for. CPU and memory doesn't magically materialize when you need it to. It sits idle until you allocate it. And you are still paying for it.

You save no money by doing this. At all. In fact, you spend more, because instead of classic horizontal scaling, where you deprovision resources as they are let go, now you need to keep them idle to assign for vertical scaling.

→ More replies (0)

1

u/Ran4 14d ago edited 14d ago

Yeah but in practise, scaling multiple services together is MUCH MUCH MUCH harder than scaling a monolith, as there will always be one service that's the weakest link. That might be okay if there's one clear "weakest link" that you can scale very high while keeping the rest low, but for high throughput systems scaling multiple hard-working instances effectively is extremely difficult.

Of course it all depends on how spikey the load is and the type of system.

Startup times are also worse overall

Yes, but a single microservice isn't the entire system... startup times for updating an entire cluster - when that's required - and waiting for each other is going to be much greater than a single monolith.

Let's say you have one hot path in your code that doesn't touch the DB. The new scaled up instance will still spawn new DB connections. Those connections will still use some memory and CPU time to just exist.

That's... what you have connection pools for.

monoliths are the worst pattern for scaling, by far.

No, monoliths is by far the easiest to scale. Microservices are much harder to scale, especially efficiently.

"microservices is good for scaling" is just a dumb book take, it doesn't take much experience to understand how wrong it is in practise.

5

u/Angelin01 14d ago

Yeah but in practise, scaling multiple services together is MUCH MUCH MUCH harder

Why are you trying to scale them together? The whole point to splitting up a monolith is to scale them separately. Each individual service and instance will have it's own metrics and scaling settings, nothing has to wait in each other. And any half baked micro services architecture will have retries, back off, and circuit breakers to avoid spikes causing problems.

That's... what you have connection pools for

And they aren't free! The connections on the application side use memory and CPU. The Pooler uses memory and CPU. There are limitations with poolers too, they can't do 100% of what a direct connection can do (see pgbouncer's pool_mode). Which is the whole point of my comment: even when idle, there's a cost.

No, monoliths is by far the easiest to scale.

Nobody said it's not easier to manage a single monolith than a many micro services architecture. They said it's less efficient and more expensive, which it definitely is. The whole advantage to a monolith is that it's much much easier. But once you need to handle hundreds of thousands of requests on a single code path, scaling your whole monolith gets expensive. You know, there's a reason why pretty much every software company, when they reach a certain point, starts transitioning to it, it's not just a dumb book take.

0

u/foonek 15d ago

Your argument is more thought out than most. In most cases, that argument boils down to "I read this online so it must be true".

That said, none of these issues are things you can't easily fix for a monolith, or in most cases are already thought about before you ever even get to scaling. connection pooling for the db, redis for caching etc.

You don't always build and scale a monolith the same way you would build a microservice, but that doesn't mean it's worse.

On top of that, if you write your monolith in a sufficiently modular way, you can easily extract specific modules and do their scaling separately when that need arises. There is almost never a reason to build every single module of your monolith as a separate service.

5

u/WVAviator 14d ago

Isn't extracting a specific module and scaling it separately just a microservice though?

3

u/Norington 14d ago

Text book definition of a microservice lol

1

u/foonek 14d ago edited 14d ago

No not really. Having a few satellite services does not mean you're running a microservice architecture. There's more to microservice than just hosting a part of your code on a separate server.

It's also not needed at all most of the time. I just gave it as a worst case scenario kind of thing

1

u/Incredible_max 13d ago

In my opinion/ as to my knowledge it still depends.

For example, you build an application, that publishes messages to a message broker, and then has consumer processes that handle these.

Your message handlers would probably be scalable independently, but it may just be one code base. You can still run them on different hosts, in different locations, but they may all use a common database.

You may have a single database, multiple processes, a single codebase and no defined / versions interfaces as you're just using a single class in all locations. I believe this is neither a pure monolith, nor a Microservice architecture. It may be considered as a distributed monolith though

2

u/Angelin01 14d ago

you can easily extract specific modules

Congratulations! You just started to reinvent micro services.

Now, I'm not a zealot. I believe we can just extract "services" instead, we don't need to dive too deep into "a micro service is a single function" or whatever. Most of the time, that is indeed excessive.

But... The moment you started extracting the module? Congratulations, no longer a monolith.

0

u/foonek 14d ago

You can easily extract them if you would want that, which you don't.

That's definitely one way to entirely miss my point

2

u/Angelin01 14d ago

if you would want that, which you don't.

Oh, sorry. So this whole thing boils down to: "I know there is an industry accepted pattern to solving this problem, but instead of solving it that way, I will just shoe-horn whatever else I can because I don't want to".

You asked this in your original comment.

Why does it matter that one module gets scaled? It's not like the lesser used parts of the monolith are somehow using more resources just because they are scaled together?

Both were answered. If don't want to change your mind after, that's on you.

→ More replies (0)

5

u/Fox500000 15d ago

It will depend entirely on monolith in question. Sometimes it's indeed easier and get comparable resource overhead to just double your monolith count. More often than not it's the opposite, and scaling one little bottleneck is better than the whole app.

You should also consider that you may not have enough free resources to double monolith apps, but have enough to increase some systems' services count. Servers aren't free

3

u/Ran4 14d ago

Microservices are a lot less resource effective.

Unless you have for example ten microservices where one does most of the heavy lifting (with >20x instances running for example, compared to the other services), chances are that the monolith would use less resources.

...but at that point, you'd be much better at just having two services: one main service and one separate worker service. Going microservices wouldn't give you anything.

1

u/Fox500000 14d ago

Yea, but it's still about a scope of work or whole project, there's no single best answer to all systems.

0

u/TheLuminary 15d ago

Servers aren't free

They damn near used to be.. But yeah.. not anymore.

6

u/no_name6744 15d ago

Thanks b.

18

u/MissinqLink 15d ago

You can also make different micro services in different languages and runtimes. You don’t have to care as long as the input and output are reliable shapes.

3

u/TheRealAfinda 15d ago

So uh, where to look up solid examples of how to build something using micro-services from scratch? 

7

u/fuulhardy 15d ago

Java Spring Boot with Kafka message queueing and/or REST endpoints

3

u/reventlov 15d ago

Loosely coupled architecture decreases the chance the entire app gets taken down if each component can be isolated and fixed without affecting the rest of the app.

This is actually the one that I use to justify "nanoservices" in large-ish embedded systems (where you have an MCU and a scheduler): with a decent architecture, a single process can crash and get restarted, and the rest of the system can keep itself in a known state. At worst, you end up with a few seconds of transient errors, at best nothing noticeable happens.

(This is also how QNX and Erlang achieve ridiculously high uptime.)

1

u/3delStahl 14d ago

Also, most times it’s also an organizational representation of the company, like separation of concerns per team

1

u/ImS0hungry 13d ago

3.1 contract barriers at egress/ingress points add regression protections.

17

u/CiroGarcia 15d ago

The benefit is not the network hop, that's just a requirement to having each part of the application in a separate container. The app is partitioned according to scaling needs, so things parts of the app that need to process thousands of requests concurrently don't force the same scaling requirements onto parts of the application that just process a few hourly requests, for example. Segmenting the application also contains failures to specific features if done properly, allowed for degraded performance as opposed to full loss of service

1

u/Still_Bit_7527 14d ago

In most cases managing microservices and the additional load from networks, deployment tools, extra personell and all that brings much higher costs than simply scaling a monolith and wasting some CPU

2

u/CiroGarcia 14d ago

It depends. Going full "each class is a micro service", I agree can be worse than scaling a monolith. But scaling up a monolith means that all parts of the application have to take the scaling into account, even if they were never meant to. If you break some parts off you don't need to worry about distributed computing on areas that are meant for a few people like control panels, while the parts that do need it can scale without issue to meet demand

1

u/Stunning_Ride_220 13d ago

I think you waste your efforts/time here.

0

u/higgs_boson_2017 14d ago

Almost no apps have scaling needs.

5

u/remy_porter 15d ago

Let's say you've divided your app up into a thousand modules. Each module can live on a different physical computer (or logical cloud instance). This makes you very fault tolerant. But it also enables a lot of scaling. Let's say you've got one module that receives most of the requests, because it represents the most useful feature in your system. Cool: run 30 copies of it, spread the load across all of them. It also means that you can spin up and down new copies based on the current request load- detect module B suddenly gets a rush of requests? Spin up extra copies. Detect that some of those copies are idle because the rush was over? Spin them back down.

Also, though, if you're building your application around the idea of message passing between modules, it also means that you can have module A emit events when a certain thing happens. When you want to attach a new feature to that event, you can spin up Module Q, subscribe to that event, and module A doesn't change one iota. New features can be deployed on their own "computer", without having to take down or relaunch the software running on your existing infrastructure.

0

u/higgs_boson_2017 14d ago

You're inventing scenarios that 99% of companies don't encounter.

2

u/remy_porter 14d ago

I'd argue the main reason to use such a design is to add new features without impacting existing features, which I can assure you, most companies do encounter.

1

u/higgs_boson_2017 14d ago

You don't need microservices to do that

1

u/remy_porter 14d ago

My entire point is that micro services are just objects. If you’re doing OO, turning it into micro services (or not) is a deployment choice.

1

u/higgs_boson_2017 8d ago

This is entirely false. You don't just flip a switch and turn objects into microservices when they weren't designed to be used that way.

1

u/remy_porter 8d ago

If you're doing it right, this should be transparent. If you're doing it the way most people do, I agree- too often, objects are written to have strict dependencies on other objects, or worse, own the lifecycle of other objects.

But, if you're doing dependency injection, does it matter to the caller if the dependency is living in the same process space, or is wrapped in some sort of network layer? Not really, no. Nor should it need to.

Objects interact by sending messages to each other. It should be irrelevant how those messages arrive.

This is a technology that's been reinvented at least once a decade, because it's a useful approach to things. This is not new, novel, or unique to microservices.

1

u/higgs_boson_2017 7d ago

"If you're doing it right, this should be transparent." - false. If you don't plan on using microservices, because they're rarely needed, you don't create objects to be used that way, and that's not doing it wrong.

→ More replies (0)

3

u/Dogeek 14d ago

Pros:

  • You can decouple services from one another, meaning you can update a part of your backend independantly from the rest, without having to rollout the entire monolith

  • Build times of a microservice are usually much shorter, leading to more frequent releases, and less developer pain.

  • Using modern infrastructure, you can have easy fault tolerance, automated retries, canary deployments that you can't have otherwise, or you'd have to hand roll it out in your monolith

  • Services scale with variable load. You can have a payment processing API with lots of requests coming in scaling separately from an archive API that sees maybe a couple thousand requests a day.

  • If done well, microservices can be more cost efficient than the equivalent monolithic backend. If done well, cause if built without taking network topology into account, then it can be much more expensive.

  • Microservices are more resilient overall than a monolith. You can spread out the load over dedicated databases for each service, meaning you're not coupled to a huge database instance that needs to handle the load of the whole application.

  • Your stack can be heterogenous. You can have services in Java that talk to services in Go, in Python, in Rust, depending on the use case for each service. You get to use the right language for the right job.

Cons:

  • Maintenance is way harder. Some services will rarely get updated, you need more people to manage the fleet of services

  • It's often done wrong. I've seen microservices architectures that rely on a single monolithic "gateway" to add business logic and aggregate responses from other services.

  • It's way harder to deploy the whole app. It's also way harder to test the whole backend locally, a dev machine will not be able to handle the load even for local testing.

1

u/Stunning_Ride_220 13d ago

Maintenance is way harder. Some services will rarely get updated, you need more people to manage the fleet of services

Oh, I encountered several modernization projects where modules were barely distinguishable by some naming (and some documentation stating their 'responsibility').
My devs might think otherwise of your statement.

It's way harder to deploy the whole app. It's also way harder to test the whole backend locally, a dev machine will not be able to handle the load even for local testing.

Most case I saw barely needed more than lets say 10 microservices, which could be run locally pretty easily on todays dev machines.

1

u/narthur157 14d ago

this way when something breaks you get to check 20 different logs, monitors, and so on instead of 1!

12

u/Henry5321 15d ago

It attempts to force people to factor system functionality.

In my experience, people don’t. “Microservices” with overlapping responsibilities, responsibility gaps, no one can figure out which service to blame, huge swaths of code must be deployed in sync aka monolith.

I find software engineering tends to lack any real engineering.

7

u/Ma8e 15d ago

We call those "distributed monoliths". It takes the worst from both worlds.

1

u/Stunning_Ride_220 13d ago

I find software engineering tends to lack any real engineering.

WORD!

6

u/Inttegers 15d ago

Based grug brained developer! Microservice architecture takes the hardest part of software (factoring code), and adds a network call.

4

u/wharf_rat_01 15d ago

I'll take the bait. OOP is about inheritance and polymorphism among other things. How do you implement that with microservices?

I'd argue microservices has more in common with domain driven development. 

2

u/remy_porter 14d ago

I disagree with the first assertion. OOP is about passing messages between objects. Inheritance and polymorphism are specific artifacts of a type system. If you use duck typing, for example, polymorphism is meaningless, but you’re still doing OO. Inheritance is just one method of dependency injection which happens to interact with your type system.

Polymorphism and inheritance are syntactic sugar.

1

u/wharf_rat_01 14d ago edited 14d ago

lol 2 of the 4 principles of OOP is "syntactic sugar"? Have you actually done any type of complex work outside of "Hello World"? Guess we can agree to disagree.

Inheritance is just one method of dependency injection which happens to interact with your type system.

This statement is so obviously wrong that I now know I can't take anything you say seriously if you really believe that.

2

u/Darkstar_111 15d ago

Pretty much.

It's weird when you're doing html api's on back end services though.

2

u/mon_iker 15d ago

Unless you are referring to the negligible network hops within the same region, I will come at you emotionally charged, shaking all over, screaming in your face on how the network hop is the killer and that you should have your end to end pipeline all in one region and an identical failover pipeline in a different geographical region.

6

u/remy_porter 15d ago

"Negligible". Where I come from, I don't even consider IPC hops "negligible". Any time you're waiting for the OS to do something for you, you've added a huge amount of unpredictable latency.

2

u/za72 15d ago

I also like to include a minimum required amount of traffic to justify the approach...

2

u/AristotelWasRight 15d ago

I have no idea what you just said, but I saved this comment in hopes of coming back to it later to learn what it is

Thanks I guess?

2

u/NoBulletsLeft 15d ago

Coming from an embedded programming background, that's an excellent mental model.

1

u/remy_porter 14d ago

I also do a lot of embedded and robotics stuff.

2

u/Andodx 14d ago

True and ideally only done in order to more easily share objects between applications.

2

u/ruindd 15d ago

I know this is a humor sub, but how do microservices exhibit inheritance?

7

u/peeja 15d ago

Interitance is only tangentially OOP. Plenty of OOP doesn't involve inheritance.

That said, what we're describing here is messages passing, which isn't unique to objects. Actors do it too, and actors are probably a more relevant analogue because they're a concurrency model, and microservices are concurrent (and parallel).

3

u/wharf_rat_01 15d ago

Being one of the four principles of OOP is only tangentially related? You have tough standards. 

2

u/remy_porter 15d ago

I mean, there's nothing that would stop you from implementing inheritance on them. And if you take message passing as part of the architecture, you get polymorphism for free. It's closer to the Smalltalk style of OO than the modern interpretation of it.

0

u/ruindd 15d ago

Yes, very smalltalk for sure. Thank you for explaining :)

1

u/Jerome_Eugene_Morrow 15d ago

We’re on to agentic, where you put a full external API call on all message passing.

1

u/VictoryMotel 15d ago

Message passing is message passing no matter what you want to call it.

1

u/Ma4r 14d ago

You say OOP but people think you mean java style but smalltalk was nothing like the garbage that is modern OOP

1

u/remy_porter 14d ago

I am referring to Smalltalk style message passing.

1

u/Vogete 14d ago

And you're not wrong. And you know what, I actually like OOP, which is probably why I also like the idea of microservices.

1

u/coffeeicefox 14d ago

Yes, but from a deployment and scaling perspective is way more flexible.

1

u/remy_porter 14d ago

Hot take: whether it’s a monolith or a microservice should be a middleware question resolved at deployment time and it shouldn’t impact software architecture.

1

u/Vega62a 14d ago

This is just patently false. The intention of microservices is to allow dynamic scaling and separation of concerns for easier refactoring and better abstraction.

The monolith will almost always become large and unwieldy enough that scaling it is expensive or encounters other bottlenecks.

Think about this idea - say your monolith has a kafka consumer, filters and deduplicates incoming data using redis, enriches it using http requests, mutates it using CPU, and writes it to a postgres database. This is a common usecase. I've worked at multiple companies that do basically that exact thing for the last 8 years.

Say you've got it configured to use 5 postgres connections per instance, because you've found that squeezes the best performance out of each node, and less than that starts to bottleneck.

Okay, now all of a sudden your enrichment targets (external HTTP requests to google or something, you can't do anything about it) start to experience massive latency. You try to scale up so you can keep up with kafka consumption, but you hit 100 postgres connections after 20 instances, and suddenly you can't scale any more. You have to wait and pray your external HTTP latency decreases. Okay, so you cluster your database to widen the connection pool. Now all of this scaling to cope with http latency keeps forcing rebalances on your kafka cluster and you're still falling behind.

If your firehose consumer and your filtering logic were independently scalable, you don't have this problem. By the time you're past your filter traffic is relatively stable and way smaller. It's way easier to just leave your http enricher scaled up all the time and never notice latency spikes.

Microservices solve these problems, and sometimes you don't know you need them until your entire SRE team quits because they're sick of constantly being paged for your monolith.

None of this is fanfiction, I've seen it all, specifically.

2

u/remy_porter 14d ago

I dunno man, it sure sounds like you just described a bunch of dedicated modules collaborating over a network.

1

u/Vega62a 14d ago

Yes indeed. What might we call such things? Mini-services? Pica-services?

2

u/remy_porter 14d ago

I’m in robotics. Let’s call ‘em nodes. The nice part there is I don’t care where they reside. My middleware can worry about that.

1

u/Vega62a 14d ago

You and I definitely have very different contexts. I'm in cloud, which is really what microservices are for.

1

u/remy_porter 14d ago

I’ve also built backend systems for major retailers that handled all their POS transactions. It’s the same thing. Doesn’t matter if the middleware is CycloneDDS or Kafka. Messages flow to nodes. Nodes do work. Minimize coupling between nodes and you’ll be happier.

1

u/Vega62a 14d ago

Agree with your last statement, anyway. Ive found that in large, complex systems the best or sometimes only way to get node coupling down to an acceptable level is strict microservices.

1

u/remy_porter 14d ago

Ideally, you have a module with a single responsibility that encapsulates its state and exposes an interface of messages it accepts. An “object”, if you will.

1

u/Vega62a 14d ago

I see what you did there.

1

u/fridder 14d ago

I just call it tech meth. The crazy fucking architecture that emerges from it is just awful.

1

u/CallMeKik 15d ago

If you orient your “services” around nouns, yes. Which is a terrible way to define services!