105 comments

[ 3.1 ms ] story [ 128 ms ] thread
It makes no sense. Why not just create modular monolith?
Because all these idiots who pitched microservices super hard need to undo the mess they've created while self promoting themselves into new thought leadership roles.
Uffff

Spot on.

And how do you know you’re not a thought leader? You call yourself one

Yeah, I was just talking to the CEO of a startup that I built the tech for, and still have a small equity stake in.

They formed a partnership with some dev shop that's going to rebuild everything that I made (that's working great and scales well).

I asked her why, and she said "because they say that doing microsevices on Azure is better architecture".

There goes that bit of equity, I guess.

/shrug

That's terrible, so sorry
Is it the fault of the thought leader, or the loads of juniors asked to implement the architecture but don't really understand it? If everyone had better system design knowledge, it wouldn't be so bad. 90% of the engineers in my organization don't understand the function of an API Gateway, for example. So the thought leader does propose a reasonable solution, but then it doesn't work because the organization doesn't have the hard skills necessary to deliver. I'm sure there's other reasons microservice-based architecture fails, but in my experience, this is a primary reason.
I feel this comment might go over people's heads if they take the connotation of a "though leader" as someone who makes a mess of things with overcomplicated solutions and then leverages it to greater roles before the consequences of the mess are discovered.

However, I've definitely seen this problem even with legitimately strong, seasoned technical leadership, where the vision is great, but the team just doesn't have the skills to pull it off. You can't have good macro-engineering without good micro-engineering. The problem with the cambrian explosion of tech is that it obfuscates the basics that engineers need to understand. Junior engineers end up struggling just to stay on top of incidental complexity and many come to the conlusion that building good software is just about learning enough languages and tooling, when in reality they are barely keeping their head above water and never learn the deeper lessons of what works and doesn't in software systems.

> juniors asked to implement the architecture but don't really understand it?

Can you reasonably expect a junior engineer to push back here and generally get traction? If this architectural decision has been made, it’s been made. At higher levels.

>If everyone had better system design knowledge

I don’t think this is a junior devs fault - they’re junior, after all.

> but then it doesn’t work because the organization…

Bingo.

I can think of a few cases. For instance, say you want to make parts of your codebase open-source and self-contained, but others closed-source. It can be easier to carve off the OSS and treat it as if it were a third-party application.

That's not the case here, where the code lives in a monorepo but the services are many.

In that case it would be just as easy to have the OSS app be used directly by the closed source app instead of spinning up another service. It could be a library, a plugin, or even just a separate app that your internal app shells out to. Basically, a separate OSS release really shouldn't be a consideration for deciding to run it as a separate service or not. Though it is an excellent reason for a separate repo.
On a large/quickly growing team the risk is folks begin to not respect the modularity and you end up with just a regular monolith

Perhaps formalized abstractions around these barriers is a good idea? At the very least better than the 60 kubernetes services at my 100eng headcount team? :-)

One major criticism I have of the way modules work in many stacks is that the dependencies between modules are hard to visualise and/or manage. Certainly in the C#/.NET world it's very easy to accidentally end up with one module depending on another that depends on the initial module via some chain of dependencies. And it's too easy to add extra dependencies to some low-level module that's supposed to be a "core" base layer module that's used across the board. That's less of a problem with microservices, esp. in a multi-repo environment, where you can enforce boundaries more easily. It's one of the few points in favour of microservices, from what I've observed so far - that you can safely make a change to a particular microservice and know a) it's definitely not going to break the CI/CD pipeline for the rest of the product b) if you have introduced a bug, there's typically very limited impact it can have.
Exactly. On the JVM (at least, dunno if C#/.NET has a similar mechanism) you can technically get away with using OSGi which can load things into separate classloaders along with all implementation-dependencies such that you can truly separate the API of a dependency from its implementation.

Alas, support for OSGi in the general ecosystem is abysmal, and the next best thing seems to be microservices.

Honestly, I find it pretty shocking that so many mainstream languages don't support this sort of "local isolation" better. The diamond dependency problem well-known at this point.

(To be clear, in our shop we generally only do this for very problematic dependencies that have a tendency to break backward bincompat on a whim. Those are almost always the most painful ones, especially if they are in turn dependended on by many of your project's other dependencies.)

Most devs, even senior, have no clear idea what a modular monolith is, let alone implementing one
This is a way to modularise a monolith. It just happens to also be a way to allow it to build out to a distributed deployment.

I hesitate to say "microservices" because I strongly suspect that the 95th-percentile use case will see all the parts strongly coupled and deployed as a single commonly-versioned blob. Not saying that's a bad thing necessarily, but if one of the benefits of microservices is loose coupling, it's not going to encourage a good microservice architecture.

I’d rather compose my systems with widely understood and commonly used components that make hiring and maintaining over time more of a puzzle problem than a, “learn a new framework” problem.

This feels like we make our jobs harder than they have to be, sometimes…

I’m working a short term job (while they find a FTE hire) for a friends startup since their last SDE quit unexpectedly. The last employee tried every framework and architecture pattern under the sun. This company has more micro services than employees and customers combined. Each one is like ~200LOC, uses a different framework, etc.

I’ve spent the last month just deleting shit and simplifying shit. You don’t need a caching layer for customer data when your entire SQL database is 100 rows in a single table. You don’t need service discovery when everything runs on one node.

My point is that this entire system was designed around their last engineer’s bookmarks of interesting things, not designed to be maintainable or easy to iterate upon.

Blame a few things:

1. The developer, of course.

2. The person who let them do it.

3. The eight thousand devtool companies that pitch their solutions to developers.

4. The hiring managers for whom 'resume driven development' is effective.

5. The VCs who wrote the playbook for how all these companies (and the dev tool companies) have to grow.

6. The Fed for so much ZIRP that VCs are in power.

7. The government for uncontrolled spending that needs low interest rates to sustain.

8. The electorate for electing the government.

9. The media for influencing the electorate.

10. The human brain for being susceptible to influence.

11. The developer for having a human brain (well some do)
It might've also been CV Based Programming.

You just pick the crap that looks good on your CV and use that. Repeat until you get a new job.

> I’d rather compose my systems with widely understood and commonly used components

OP here. Fortunately the authors of the components you use didn't get discouraged by comments like this otherwise they would've never been written ; )

Yeah well they wrote useful things.
How about just stop making microservices and go back to monoliths? Then you don’t have to shoehorn two things at the same time!
I spent a decade at Amazon (SOA all the things!) and then a year and a half at Shopify (single Rails monolith for all the things!).

I think both strategies have pros and cons. But critically, you need a company culture that supports whichever choice you've made.

If you have a company where each team gets to totally decide how they want to implement their stuff, sharing a monolith between teams can create a mess. Ownership issues to be resolved, code quality/style issues, operational issues. Monoliths require alignment.

> Monoliths require alignment.

So do microservices.

I think GP's point on company culture is the right answer.

My only thoughts to add is monoliths can be aligned as well as microservices, if not a bit easier depending on the team.

You have to align microservices to talk to each other anyways, and there's no reason you can't make those boundaries work in one codebase instead of many.

That said ownership is more important in a monolith, whether that be a single team of architects or architects responsible for a specific well defined part of the code base.

Having a solid process for only allowing well thought out code in is a cornerstone to keeping alignment.

The worst thing is the many-monoliths/mini-monoliths problem that you get when each team thinks it has ultra special needs and absolutely must build everything from scratch, even if it’s a near duplicate of something someone else built 2 months ago.
building from scratch instead of using something that already fits pretty well is orthogonal to discussion as it happens both in monolith and microservices
(comment deleted)
Out of curiosity, do the microservices at Amazon typically call each other in an orchestrated fashion (i.e. microservice A knows it needs some particular functionality and knows to call microservice B to get it), or is in more asynchronous/"choreographed", where requests are available to a general pool of services, each of which handles as they need? It's hard to see how a library like the one posted about here would help much with the latter.
It is definitely the first one. Microservices at AWS typically grow boundaries at team boundaries, even if it would make much more technical sense for them to be combined. Each team knows which other team provides the APIs they need.

(Under the hood, the service may in fact be distributed to a large pool of resources. But a microservice doesn't shout into a void "hey could someone please handle a LaunchInstanceInRegion class??" - it's like using a library, but over the network.)

How do they avoid cycles in calls to dependencies? Some golden rule of "thou shalt only call services that are less abstract than thyself?"
In my experience building these type of microservices, it just doesn't really happen often. Team A is responsible for customer data, Team B is responsible for inventory data, so you are usually don't have situations where A calls B and vice versa. The checkout service knows to call A and B.
I have yet to work at a company where teams were so discipled in their silo with API version control and backward compatibility that it did not require cross-team alignment. This is largely a theory and a myth.
Microservices: Software complexity solutions to human organisation problems.

Remember when microservices were pitched as 'allowing you to use the right language for the job'? What a wonderful life the person who thinks a balkanised tech stack is good must have had. They're one undisciplined developer away from having production prolog.

One of the pros of microservices is that each individual microservice is so simple that it really doesn't matter what language it's written in because it can be easily rewritten.
That assumes the service is doing something generic enough to be trivial in any language, in which case, why not just choose one?

It's like we're advocating for the outcome of the Tower of Babel tale.

I mean, ultimately most languages and frameworks are/should be at least intelligible and serviceable by your teammates. I’ve both been on teams where I cannot work on Jerry’s Fucking Insanity Factory API after he leaves even though it’s written in JS and I know JS, but this is some insane Rube Goldberg machine that only Jerry’s mind understands, I’ve also been on teams where someone will write their thing in Go or Rust and I don’t know those but I can at least maintain them, because they’re well abstracted and do nice things and their authors were not schizophrenic like Jerry
One of the pros of monoliths is that each individual functionality it provides is so simple that it doesn't need to be rewritten.

Micro services replace your unmaintainable bean injection XML abomination with 50 reimplementations of database access and a salary for the one guy who knows his to make your kubernetes setup work.

It's not a technology problem, it's a people problem. Micro services make it a distributed people problem.

> One of the pros of monoliths is that each individual functionality it provides is so simple that it doesn't need to be rewritten

I... I don't really understand this sentence.

probably because you are replying to a quote of a quote, but didn't read the quoted comment? spend more time reading and less time writing would be my suggestion to help with understanding the comments here.
> probably because you are replying to a quote of a quote

Its not a quote of a quote, its an attempt at a mocking modification of an upthread comment that isn’t a quote, but the original doesn’t fix the incoherence of the mocking reply.

I wrote the quoted comment.

You'd probably notice that if you were to spend more time reading and less time writing.

I disagree that this is the case; decomposing into microservices doesn’t mean that the functionality within a service boundary is trivial and easy to rewrite.
Of course, there's a whole continuum of complexity between microservices and monoliths in real life. Much of that continuum is labeled as "microservices".

I personally think that if microservice is doing something so complicated that the rewrite would take we-cannot-afford-that amount of time, then it should be split into multiple parts.

My (small) team spent a year rewriting one simple clojure/mongo CRUD microservice into Java/Postgres. The process was anything but easy.

Interestingly, even a simple CRUD can be made in a complex way in Clojure which makes it difficult to understand for non-clojure devs.

Data migration path is also a huge issue (and the major reason it took so long).

I believe the original service took 6 months to develop (including all iterations of the design/spec), a "simple" 1:1 rewrite a double of that.

That would be extremely irrational, to throw away money spent on designing, developing, testing, benchmarking, optimizing, debugging weird bugs, fixing that service just because you like another language.
Are there actually many real-life examples of large-scale microservices architecture operating successfully with a range of different languages in use? I did (briefly) work at such a shop, I can't say the experience was particularly rewarding, but I was expected to be on top of ALL said languages/stacks and their various idiosyncrasies etc., and much of the code was pretty poorly written. Arguably the biggest challenge was maintaining the build system!
I haven't heard of any, the classic 'allowed languages' pages of tech companies come to mind.

"You build it you run it", until the OCaml guy quits and now you need to support OCaml.

I do recall speaking to people at a betting company many moons ago who tried to recruit me with the claim they were so open with microservices that they had a key system written in Erlang that only one engineer in the company understood.

I politely explained my position on why that seemed suboptimal.

That's good, when I had to consume their API it was closer to zero engineers who understood it.
I've worked at a place where it was a case of choose what you want - there's lots of C#, Python and Javascript, some Go but there's still Scala and CoffeeScript lurking around, as well as some other more esoteric stuff that seemed like a good idea at the time.
Would you describe it as a "large-scale microservices architecture operating successfully" though?
Yes and no - it definitely runs and makes a lot of money, but sometimes things mysteriously go wrong and no one quite knows why (service x is running slowly because service y is running slowly because service z is running slowly and no one knows why service z is running slowly), and it's reached a point where most new work is done in yet another microservice, so headcount keeps slowly growing (usually throwing more offshore contractors at it) to deal with the problem.
Most (successful) paths lead to balkanization. Just one acquisition can do it, much less 2 or N more. And the pace of these changes can outpace your ability to respond to it, which makes fighting it a losing battle.
Yes, it is inevitable at some level, but supporting 2 different stacks (result from acquisition) is better than 20 (result from "pick the best tool for the job" culture).
(comment deleted)
That's a "nice to have" problem down the line. What I've seen is the insanity of microservices being adopted by one-pizza-team startups.
Been there, except I was the pizza being eaten by 5 microservices.
Hi, author here.

I agree 100%. However after spending 10 years doing microservices everyone wants me to do microservices, despite me telling them what you just said. It's a positive feedback loop.

This project is just an exploration of providing teams with a low (no?) cost way of doing microservices - I also kinda enjoy hacking on things like this. Still in progress though so use it at your own risk.

i think a lot invest in microservices as the services require less programming skills. ofcourse, the whole thing requires skills, but little services with simple apis are easy to make.that makes hiring a lot easier and maybe cheaper. i love monoliths, but at my company (not a software dev place) its hard to do these things. most people dont understand threads and architecture of programs, but they can make some fastapi routes and hook them up to some functions. we can create complex things despite their lack in pure software dev skills. (i wish it was different! but u have to work to ur teams strength othetwise it will end in tears!)
how about proper system design, make "procedure calls" workable both locally and "remotely" ?
Even better, why not go back to modularity? Many microservices could be just that: self contained modules that you can swap in and out as you see fit.
It's really disappointing to see this kind of lazy oversimplification being the top comment on HN, as if monoliths were perfect and microservices didn't have any advantages over them.

Yes, maybe the company you work at does not have a good reason to use microservices. But this doesn't mean the same goes for the rest of the industry. Being a nay-sayer and rejecting microservices in any circumstances is just as unreasonable as rejecting monoliths.

> Being a nay-sayer and rejecting microservices in any circumstances is just as unreasonable as rejecting monoliths.

No. No no no no! Monoliths (modular or otherwise) are the default and if you have to ask, you don’t need microservices. Period. That’s not a lazy oversimplification, that’s hard earned experience.

In over 15 years I’ve seen microservices singlehandedly kill the engineering momentum at nearly half a dozen companies. They’ve got a worse track record than techbro management. Literally the only time I’ve seen the architecture work well was when I was working at Azure on cloud infrastructure with a dozen teams working on a single product. The vast majority of developers never work on a project of that size and yet try to cargo cult microservices into companies with less than a dozen devs, let alone teams.

Maybe your company is one of the few companies where microservices make sense (or you haven’t come to grips with the stockholm syndrome yet), but the hype around microservices have been a disaster for many more companies than they have helped in my career

> No. No no no no! Monoliths (modular or otherwise) are the default and if you have to ask, you don’t need microservices. Period. That’s not a lazy oversimplification, that’s hard earned experience.

But this is not what I am arguing. Yes, monoliths are the default, and unless you reached the point where you have thousands of engineers and teams working completely independently, you don't need microservices. I've also seen momentum being killed by microservices in smaller startups, and I've also seen large organizations operating with microservices wonderfully.

My beef with this kind of comment is that it kills any interesting discussion about architecture into a "don't use microservices" circlejerk, which is not helpful to people who actually want to dive into this kind of architecture. As you said yourself, microservices do work well for large companies, so why pretend it doesn't?

> As you said yourself, microservices do work well for large companies, so why pretend it doesn't?

Same reason we don't teach people anything about driving an 18 wheeler when they apply for their regular driver's license. A small minority of drivers will ever even have to think about the topic and when they do, they'll seek out a specialized trucker school or their employer will guide them through the process using institutional knowledge. There is zero value to exposing people with learner's permits to the nuances of driving massive trucks.

Unlike the truckers, however, tech bloggers have hyped up the concept of microservices as a panacea to all developers, resulting in a disastrous cargo cult. There is no interesting conversation to be had about microservices in this context. That discussion is going to be had with all the other senior-most engineers in an organization because any org incapable of such an in-depth discussion internally should not be using microservices.

I wonder what the rationale behind AGPL is? Prevents it from being used for commercial SaaS
That is usually the rationale behind such licenses, yes.
My issue with microservices isn't the network calls, it's the extra work to keep the source code up to date.

New spring library? Have fun applying the same changes to 14 different microservices.

Microservices might make sense with completely different teams developing them - but multiple microservices in the same team, with the services talking to each other, really doesn't make sense.

> New spring library? Have fun applying the same changes to 14 different microservices.

On the flip side, at some point monoliths can get large enough that upgrading libraries or runtimes becomes an incredibly difficult problem. When I was at Amazon a major service was finally getting upgraded from Java 7 to Java 8. Took a cross-functional team 6 months (!) to make it happen due to the massive amounts of existing code. And these are AWS engineers who are much technically stronger than average.

I don't condone the 500 LOC style of true microservices, but people tend to go back to the extreme of "just make everything run in the same process with the same runtime and same dependency chain" as if that doesn't come with its own set of headaches.

(also for what it's worth -- in correctly done SOA, you don't need to upgrade libraries in lockstep. So that Spring upgrade can be done on a per-service basis as needed.)

> at some point monoliths can get large enough that upgrading libraries or runtimes becomes an incredibly difficult problem

Some languages (e.g. Go) make this easier than others by allowing two versions of the same import to coexist, but this is why we broke up our Django monolith a few jobs ago.

Yeah, the library problem has some (ugly) solutions in some languages, like Go allowing multiple versions as you mention, or doing JAR shading in Java. But I don't think there's a (mainstream) language that solves the problem of partially upgrading the underlying runtime. If you've got a Java monolith, it either all runs on Java 7 or Java 8, can't really do in-between.
Wouldn't they similarly need comparable amount of time to update all 14 microservices?

IMHO unless you have a strong engineering culture, having the same dependencies is the only way to ensure they are all properly updated (regarding security updates, and replacing deprecated dependencies/versions.)

> Wouldn't they similarly need comparable amount of time to update all 14 microservices?

In my experience doing this at AWS and elsewhere, no, the services case is much easier. Even just the ability to do releases in chunks 1/14 of the size is a huge advantage. On top of that, your services are going to have smaller dependency chains, and transitive dependencies are truly where dependency hell[0] comes into play. It boils down to complexity being multiplicative rather than additive. Depending on the size of everything, each service is probably more like 1/50th the amount of work rather than 1/14th.

> IMHO unless you have a strong engineering culture, having the same dependencies is the only way to ensure they are all properly updated (regarding security updates, and replacing deprecated dependencies/versions.)

This is working under the assumption that all your code and services should always be updated to the latest, which isn't necessarily true. I still have smaller, infrequently updated services running and happily chugging away that run on Python 3.5. Other codebases have been upgraded to Python 3.10, sure, but what's the harm in letting this one run on an end-of-life Python, especially given that it's a backend service, with no public access, that only communicates via RPCs? A vulnerability might be found in Python 3.5 that necessitates an upgrade, but it's not like moving to the latest version of everything prevents that -- i.e. "Heartbreak"[1] only affected OpenSSL 3, not people still using OpenSSL 1.1!

[0] https://en.wikipedia.org/wiki/Dependency_hell

[1] https://arstechnica.com/information-technology/2022/11/opens...

There are always those specific cases you need to do when upgrading major versions.

The chance of a percentage of 14 microservices just plain not using that feature is bigger than the chance of that monolith not using it.

A completely contrived and fake example:

The language you're using has a complete refactor of its math library, everything must be rewritten in a new style that's incompatible with the old style.

In a microservice world there's a good chance that very few of those actually need the high-powered math library.

But your monolith has a few sections that use it so the whole shebang is delayed until that bit is rewritten to the new API.

The trick is to always be keeping your monoloith up to date on the latest tech. Shopify's monolith is always on the latest Ruby and Rails versions. I have worked at a place where the monolith was on Java 6 while Java 9 was out, so it is a valid concern. But if you are doing constant updates, it makes it more manageable.
Change to build process? That's 20 build plans you have to update.

Yeah, it's just a laugh a minute.

At one of my previous jobs, they had a "BOM" that each service inherited from. This contained most of the core dependencies (Spring, database drivers, logging, monitoring, auth, service discovery etc.) with a default configuration that worked in all environments. This was built on top of Spring Boot, so if you needed to use Postgresql, you just added the basic database configuration to your property file and the BOM would make sure that the necessary beans and service discovery was loaded.

This meant upgrades were usually as simple as increasing the version, as the infrastructure team had already made sure that the other dependencies had been tested. Each team were free to ignore this and do whatever they wanted, but the benefits were too great to ignore for most teams.

At my current job we don't have this type of shared configuration, which makes micro services much harder to maintain.

I think this is directionally correct. Services should just be standard language classes, and whether that service is hosted inside process 1 host 1 or process 7 host 5 is up to the autoscaling component. The industry is verrryy slowly getting there.
Hi! OP here.

Yeah in part my motivation for open sourcing this was the fact I kept reading on HN how microservices should be an implementation detail etc. in the past 6 months. I totally agree with that sentiment, hence Actio. For the direction I can take some responsibility but not for the details (yet) ;).

Reminds me a lot of erlang and the core features of where the function runs is unimportant.

This is solving microservices via dependency injection.

I'm not against it, but honestly if you not gonna be thoughtful about it.. Why not just monolith it? Monoliths are only a problem at large scale, and at that scale you have the manpower to create a reliable messaging service for inter service communications.

I think the point here that is getting lost here (not on you necessarily) is that if you write your service clean/SOLID, it really doesn’t matter if/when/how you make that decision to cleave it off into its own service. Monoliths are only a problem with scale, but there is absolutely no guarantee that your engineering team will scale at the same rate as your userbase. You know the story: tech product strikes gold, gets mentioned in NYT and becomes a new hot thing and doesn’t even have time to react before they hit scaling problems. It’s not great to prematurely optimize, but if you’re not preparing for eventual success (which requires scaling) is another term for shooting yourself in the foot. Unfortunately, even if you are “scaled up” in terms of workers, monoliths can be really nasty/resistant to many hands making the work lighter because they of how tightly coupled things end up being.

Why not monolith it? Maybe one part of the app evolves to really need a time series database or it really does some crazy stuff with image editing or it has new special dependencies that take an eternity to build, and you don’t want to add 20m of build time every time you mess with the rest of the codebase, none of which needs/expects the time-series/image-editor/complicated build thing to be there deployed alongside it. That’s like OG logic of why you want microservices, and it still makes a lot of sense, just people get carried away with cargo-culting on their thousand-microservice hellscapes where each API has four routes and 4000 lines of deploy config, boilerplate, copypasta.

Microservices don't solve the tight coupling problem. Rather, they make dealing with it even more painful because rather than updating assumptions across modules, you update them across different units of deployment. This leads to ossification because it is even more difficult to fix bad architecture.
I never claimed they did, I said if your code is SOLID then it doesn’t really matter if it’s a microservice or not, it will likely be useful up to the point where scaling/organizational/too many cooks/long deploy/spof problems start to crop up.
Not sure this holds water. Which SOLID principle, or combination, solves the problem of building a system where a request traverses a boundary that is not problematic when executed locally, but introduces too much latency when you put a new network call behind an interface?

From what I can see, SOLID lets you split the monolith, as long as you happen to have interface segregation on the right seams. It says nothing about the operational properties of the service once split, which is by far the bigger problem, and depends on the non-functional properties of the code using the interfaces. Unless you already know you are headed for a microservice split, you're unlikely to have designed with that in mind.

I find a lot of people conflate both service separation for human factors and service separation for technical factors.

Unless you have multiple independent development teams you do not need to worry about the human factors. Addressing them fully is always going to come at a technical cost in terms of things like latency and complexity.

Separation for technical reasons (generally scaling) may well be a factor but easily addressed without building 'true' microservices, for example with serverless functions.

Don't let the purists sneer at your architecture because it's not true microservices.

Monolithic microservices look like a perfect anti-pattern. Worst of the both worlds, so to say.
Not much is monolithic about this tbh. It's just trying to hide the architecture implementation detail (monolith vs microservices) instead of exposing it like most existing frameworks.

IMHO the monolithic microservice (or distributed monolith) is when you don't have firm service boundaries - eg. services can read each other data if they want, sidestepping endpoints/handlers.

Actio avoids that mistake. Each service has its own database.

There are a couple of relevant recent talks on the subject:

- Top 5 techniques for building the worst microservice system ever - William Brander - NDC London 2023 (https://www.youtube.com/watch?v=88_LUw1Wwe4)

- Don’t Build a Distributed Monolith - Jonathan Tower - NDC London 2023 (https://www.youtube.com/watch?v=p2GlRToY5HI)

It is such a weird feeling to come across a topic I haven't read on in a while, watch two videos on it out of random curiosity, hop on hackernews the next day, and get a recommendation for the exact same videos.

I very much enjoyed the 5 techniques and many of the tidbits. I also liked "Avoiding Microservice Megadisasters" but mostly for the entertainment value (https://www.youtube.com/watch?v=gfh-VCTwMw8)

So you are trying to build Erlang without Erlang and OTP. Nice try :) You are maybe 5% there. How about the rest? Error handling, handling network issues, latency, partitions, deployments, scaling etc...

I would also argue that because of the async calls (NodeJS is single-threaded, right?) you can easily run into weird and unexpected issues where two sequential service calls return out of order (which is impossible if they are just method calls, but very likely if they are sent over the network). How do you handle these cases? Do you just block on each call over the network and hope for the best?

That was my thought too, this has been done many times before; I'd like projects like this to show their homework and prove they've tried e.g. erlang, scala, etc for the same thing, the pros and cons, the dealbreakers (and there won't be many dealbreakers), and why building a new tool is worth the effort.
My goto for this kind of task is moleculer: https://moleculer.services/

Fast, battle tested, vue2-like approach, great documentation, good community. The automatic indipendent-scalability as an option is usually the main selling point of these solutions, but honestly I think the real pro is the "composition" approach, which is essential if you want to keep a clean and well-organized codebase. On this regard, I found moleculer pretty great even for large teams.

Why on earth would you use javascript for that? There are way better alternatives out there like Go, Erlang, Kotlin, or any other of the typical backend languages. Is it too much to ask for frontend devs to learn a new language?
Works great for applications where you spend most of the time waiting for a database.

The dynamic type system makes it easier to write testable code with less abstraction overhead.

Faster to train up junior devs.

That said, you * must * set up the codebase with appropriate guard rails or bad things can happen.

> Works great for applications where you spend most of the time waiting for a database.

You mean callback hell? :P

> The dynamic type system makes it easier to write testable code with less abstraction overhead.

My biggest issue with js/ts is that there's nothing really enforcing good code, unless you decide to adhere to it. Also: npm is utter garbage.

> Faster to train up junior devs. I think go is better in that regard, less random happenings.

But yeah, in general I get what you mean!