Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> How microservices are still a default systems design architecture in anything but the largest orgs still puzzles me.

A system that's made out of smaller single-purpose programs that are all made to be composable and talk to each over a standard interface, is not exactly an unproven idea.



Composable single-purpose modules that communicate over a standard interface can be more easily achieved without involving a network and the complexity that comes with it.


IMO, there are only a few cases where the added network traversal make sense.

1. There's some benefit to writing the different parts of the system in different languages (e.g. Go and Python for AI/ML)

2. The teams are big enough that process boundaries start to form.

3. The packaging of some specific code is expensive. For example, the Playwright Docker image is huge so it makes sense to package and deploy it separately.

Otherwise, agreed, it just adds latency and complexity.


It's actually really weird, if you think about it, that point 1 should involve the network. We should be able to just call a function in one language from a function in another language.

Actually this happened to me once. We had two components that needed to talk to each other - one with an Erlang server and C client library that communicated over a socket with a proprietary protocol - and the other in node.js. The first attempt was to write a C translator that took requests over another socket with a different proprietary protocol, but this one was proprietary to us so we could use it directly from node.js. The second, much better attempt was to learn node's C++ module interface and write a C++ node module wrapper around the C client library.

This third-party Erlang component benefited from being an independently restartable process and therefore needing some RPC, but we also had a mess of C/C++ components inter-connecting over RPC that in reality probably didn't need to be separate processes, but for some reason we'd already decided that architecture before we started writing them.


> It's actually really weird, if you think about it, that point 1 should involve the network. We should be able to just call a function in one language from a function in another language.

If you have two languages that both are not C or C++ , and have more involved runtimes, how well does this work? I know for some cases you have things like JRuby or IronPython, but say mixing a JVM language and a CLR language?


For those cases you have to bring the runtimes with you.

With JVM and CLR you can use JNI and COM to generate SOs/DLLs, and both of them can use any SOs/DLLs via FFI. There is also IKVM and Jni4Net that allowed Java code to run in .NET (or at least used to be, I last used it 15 years ago). Results may vary.

For other languages it can be a bit more involved: if there's no such thing as exposing as a library, you must embed the interpreter, which typically involves using C++.

It's not fun. This is why people end up using network requests.

If you can have a text-only interface, or even involve files, you can also just invoke the other app as a process.


The level of reductionism of that comment is honestly quite amusing given the topic. Maybe we can use it as an unintended warning of not going too far in the pursuit of simplicity.


Separation of concerns is the false promise of all these so-called "architecture patterns." Their advocates make you believe that their architecture will magically enable separation of concerns. They offer blunt knives to make rough slices, and these slices always fail at isolating relational concerns, inviting entirely new layers of complexity.

You had a relational database, designed to store and query a relationship between a user and their orders. Now, you have a user management service and an order service, each wrapping its own database. You had a query language. Now, you have two REST APIs. Instead of just dealing with relational problems, you now face external relation problems spread across your entire system. Suddenly, you introduce an event bus, opening the gates to chaos. All this resulting madness was originally sold to you with the words, "the services talk to each other."

Who ever claimed that REST services compose well? Because they can "talk to each other"? Really? Only completely disconnected architects could come up with such an idea. REST services don’t compose well at all. There aren’t even any formal composition rules. Instead, composing two REST services requires a ton of error-prone programming work. A REST service is the worst abstraction possible because it’s never abstract—it’s just an API to something extremely concrete. It doesn’t compose with anything.

Microservices aren’t micro. They’re hundreds of large factories, each containing just one small machine. Inputs need to be packaged and delivered between different factories in different locations, adding complexity every step of the way. This is what happens when enterprise architects "rediscover" programming—but from such a disconnected level that the smallest unit of composition becomes a REST API. Rather than solving problems, they create a far larger problem space in which they can "be useful," like debating whether a new microservice should be created for a given problem, and so on.

The same critique applies to "hexagonal architecture." In the end, with all of these patterns, you don’t get separation of concerns. The smallest unit of the architecture was supposed to be the isolation level where your typical problems could be addressed. But your problems are always distributed across many such units, making them harder to solve, not easier. It’s a scam. The truth is, separation of concerns is hard, and there’s no magical, one-size-fits-all tool to achieve it. It requires significant abstraction work on a specific, concrete problem to slice it into pieces that actually compose well in a useful and maintainable way.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: