Hacker News new | ask | show | jobs
by FinanceAnon 1661 days ago
Fundamentally, I don't really see much difference between monoliths and microservices.

In a monolith, you just call another function/class, but in microservices that function is a http call. I guess the benefit of microservices is the ability to independently scale different microservices, being able to choose different languages for different microservices and less conflicts in the repo as more people work on it, but you still have to deal with backwards compatibility and versioning of endpoints.

I think lambdas are interesting when you look at it this way. A microservice is essentially a set of functions which is constantly deployed as one unit. But with Lambdas, each function is a single unit that can scale independently.

9 comments

There’s a huge difference between http and function calls. When I call a function there is no chance it fails because the function ‘cannot be reached’. With services there are endless reasons why one service is unable to communicate with another. It’s a huge amount of overhead to build a system to handle inter-service communication and failure that doesn’t exist when only calling a function in the same binary.
And, you add latency issues and overhead. With a function call you pass two int and get a string of length 120 (how much memory is this? little, very little), with microservices you make an api call using http with it headers and get a json, and maybe you could need 2 api calls. For me it's easy, just create a monolith, when you become facebook or netflix, split symfony services into microservices (just an example). Oh, and don't forget the developers who translate a specific function into an endpoint, you need a change in the caller and you must change the api!
I agree, but perhaps I didn't word it the right way in my original comment. With microservices there is a big overhead in development and managing failures, but functionally it doesn't offer much more than a function call within a monolith.
> When I call a function there is no chance it fails because the function ‘cannot be reached’.

Run time DI configured from XML.

With enough Java anything is possible!

> When I call a function there is no chance it fails

I like to print statements like this one and put them in a frame on the wall.

Fails because the function is unreachable. The second half of the sentence you quoted says exactly that, why did you cut it out?
If execution of your binary is stopped some time between the call and return (with following restart), dealing with it is no simpler than dealing with network partitioning.
It is. Because then you know that the caller also must have failed. Whereas with an http call, you might want to retry, log the error, fall back to a cache, etc. etc.
This is ignoring the fundamentally-different issue that was raised, which is that the service boundary introduces a new failure point that doesn't exist in a function call. What you're describing could just as easily happen in a service call, IN ADDITION to the service just not being reachable.
It most certainly is easier to deal with the in-process version. I'm specifically referring to database transactions, which are much harder to have available in a distributed context. That failed network call complicates your life so much.
> Fundamentally, I don't really see much difference between monoliths and microservices.

> but in microservices that function is a http call

I think that maybe you're understating the complexity that distributed systems may involve.

For example, see all of the following:

  - https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing
  - https://blog.erratasec.com/2012/06/falsehoods-programmers-believe-about.html
  - https://medium.com/@kenbantoft/falsehoods-programmers-believe-about-networks-30a328c25c50
Plus, in the current day and age, we still don't have that many convenient ways to make two systems interact over a network. REST and things like GraphQL don't map well to actions, whereas RPC solutions like gRPC also involve a certain amount of boilerplate code and you still need to think about how the concerns above.
And not forgetting "A Note On Distributed Computing" https://www.cc.gatech.edu/classes/AY2010/cs4210_fall/papers/...
There's flexibility in the ops/deployment side that you don't get with simple library calls. You can take down a specific service cluster and keep your app running with slightly degraded functionality.

The blast radius on deployments can be smaller.

You've already done the work to build up IPC/networked communication so you can make big decisions in a service (like using a better suited language for some feature) without worrying about integrating it with every other feature in your monolith.

You can tailor the instance type to the service. Say you need some kind of video ingestion (or something) that is low use but needs a high memory ceiling. Would you rather pay for that memory across all your monolith instances or just run a few instances of a high memory service?

There's a lot of differences you're not thinking about.

To be fair, you CAN build a monolith in a way that is very similar to microservice architecture.

You can have a single function that handles all data base writes. A single function that monitors for failures. A single function that sends outbound notifications... etc

If these functions are call in a way that: allows for A/B testing, SUPER high latency (or no response), failure notifications sent to the code owner, automatic retries of failures, independent code deploys

Then, congratulations, you have a monolith made up of microservices!

> Fundamentally, I don't really see much difference between monoliths and microservices.

> In a monolith, you just call another function/class, but in microservices that function is a http call.

That right there is the fundamental difference.

For one thing, calling a function in the same process is going to be orders of magnitude faster than a network connection call and all that it entails. Even if performance doesn't matter at all in some use case, it's also additional cost to be running all these additional instances.

And then, complexity went up since a network call can fail in all kinds of additional ways that a jump to a function address in the local process cannot. So the code has to deal with all those. The complexity of correlating your logs and diagnostics also just went up. Your deployment automation and versioning complexity also now went up.

All these are solvable problems, of course. It just takes more people, time and budget. If the company is large enough sometimes it's worth it for the dev team decoupling aspects. If the company is tiny, it's approximately never worth taking on all this extra work and cost.

> Fundamentally, I don't really see much difference between monoliths and microservices. In a monolith, you just call another function/class, but in microservices that function is a http call.

In J2EE that difference is a configurable technical detail. You have 1 service that calls another, and the protocol they use can be a normal function call, RMI, SOAP (or I think REST nowadays) depending on dynamic configuration.

> you just call another function/class, but in microservices that function is a http call

The difference is enormous.

The new generation of devs really develops systems as if HTTP were a zero-latency concept.

This is just like those people who consider all DB calls to be "free". Not that this went away either, it's just way more egregious now.

Scale independently, and as a result can fail independently in an unfathomably opaque cascade of failure modes.

I'm a big SOA fan, but my experience with any non-trivial lambda architectures has soured me on the FaaS concept writ large.