The original goal for moving from a monolith to a microservices architecture was loosely stated as “its hard for us to work on the app together and ship features”. Something that isnt addressed in the results or suggestions.
How much did the team improve shipping features for customers? Is the app more reliable? Does the engineering team spend way more time on CI/CD and all the other “overhead”?
Most teams will never need this type of solution, even though theyre tons of fun to build and operate. I just wish we had a better way of sharing the non-engineering results of these types of efforts.
Any CI/CD overhead should not be unique to microservices though. I've worked on monoliths with fully automated CI/CD pipelines, tests, etc. I haven't noticed any difference in the amount of overhead/ALM work required between monoliths and microservices other than the number of tests, scale/time of deployment, etc.
Id welcome a good discussion on triviality in this case. Wiring up jenkins or something to just deploy when you press the button can be easy. Wiring it up so distributed services being augmented, deployed, migrated, etc all without downtime - to me at least - is complex enough to not be trivial.
IMO, CI/CD already means zero downtime deploys. After a team has done the CI work on commits and zero downtime CD, it doesn't matter if it's for a monolith or microservices. The initial work is not trivial, but once it is done you just copy it for each service.
Maybe you are thinking about how do you deploy inter-service dependencies? In that case, you don't. I'm not joking. When you move to microservices you have to treat other internal services like they are something you do not control. This means maintaining backwards compatibility, versioned APIs, etc...
At first it seems like it is harder, but once you get in the mindset that this always must run and serve existing clients it is rather freeing. Plus, being able to treat each service on its own makes it easy to focus and do large changes - thus move faster.
Compare this to friends who tell me about logging in at 11PM to deploy because they have to take the system down. Completely taking down the system to deploy should almost never happen today.
Very detailed blog with lots of wise words used, but very little actual experience shared.
For a startup - all this may feel OK like you're cheating the system and beating others to the punch - but damn, if you actually make it - good luck scaling that up.
Personally, I don't see faas a competitive market advantage. It's a tool and i'd be a hell of a lot more selective in how I used it.
For a startup - all this may feel OK like you're cheating the system and beating others to the punch - but damn, if you actually make it - good luck scaling that up.
Why is that a problem? I am speaking in C# terms...
Phase 1 Monolith: all of your code is one solution, with separate domain specific projects (assemblies) with separate namespaces with a logical use of access modifiers exposed as an interface. All of the other code uses interfaces as dependencies defined with a DI framework.
Phase 2: We need scale now. Bring up a lot more VMs at the click of a button behind a load balancer and you get scale quickly.
Phase 3: Take your project that you need to scale independently out of the monolithic solution, expose it as API, put that one API behind a load balancer. Then have a proxy class in your client and use your DI to map your interface to your proxy. If you integrate something like Swagger into your API, it can create the proxy class for you.
If you can deal with eventual consistency, use a queueing mechanism.
Rinse and repeat and keep taking projects out of the monolith as needed.
There will be some shared code you don’t want to run out of process. For that, create Nugget packages and you won’t have to change your client code at all.
I was thinking something along these lines, as well. I recently learned of the IDesign Method, which seems to try to do something like this, with a standard architecture for handling scaling in a future-proof kind of way.
Forgive me if my understanding of that architecture is wrong. I only have read parts of the book so far.
It's basically Domain Driven Design combined with SOLID principals. If you have a Customer domain and an Order domain, as tempting as it is to join the two related tables in code, avoid it. Have another service (not http service/domain service) aggregate information from both domains.
It's then mechanically trivial to split the Customer module and the Orders module both the code and the data store.
> There will be some shared code you don’t want to run out of process. For that, create Nugget packages and you won’t have to change your client code at all.
actually you can keep your solution and just have many projects in one solution (monorepo)
having one large solution causes a ton of issues. Even if you have multiple solutions in one repo, that means everytime you deploy, you have to deploy the whole thing. Rolling back becomes more difficult and one team can break the build and it effects other teams.
How do you do independently automatic partial builds and deployments to an integration environment with a monorepo? If I just changed one solution, pushed it, and the build process is automated, how does it know not rebuild and deploy all of the solutions?
> but damn, if you actually make it - good luck scaling that up
It's foolish to think that the initial version you make of any system is going to be the same thing that you end up scaling to a million users and it's foolish to think that you're going to understand where your actual pinch points are going to be before that system is under any sort of pressure. Let alone before you really know what your product is really going to be (which is the situation most startups find themselves in).
The slices you decide to make with the knife early on more often than not look stupid and burdensome once you're actually under pressure.
Most people also underestimate how far it's possible to push monoliths. My favourite example is the OpenStreetMap infrastructure, which has to support thousands of concurrent users editing a global map that is ~105G when compressed. It's largely monolithic. And that doesn't really seem to be a problem. Works well.
I suspect most people have never actually seen the sort of "heavy load" they talk about so much running on a sensibly designed monolith to the point that it's not coping due to its architecture. There's a lot of conceit around how big a load people really deal with.
nah, making stuff is easy, keeping it running and scaling it is hard. Most people just delay the hard stuff perpetually or abandon it all together in looking for something else.
I would say the complexity is largely in deployment. Otherwise, I find microservices much simpler to reason about.
As an example, keeping a bunch of small, isolated microservices behind queues means that I can reason about them very locally. I know what data they own, I know their interfaces, and I don't really need to think 'outside' fo them - they just send other asynchronous messages out. I don't need to think about dependencies very much - if a downstream or upstream server fails it is irrelevant to the microservices, so long as the queueing system is up.
It's a bit more annoying to get infrastructure and whatnot set up, but not a ton.
> expensive
Maybe? Shouldn't finger grained scaling be cheaper in some cases?
> require much higher expertise
I don't really agree. Again, by keeping things small and by maintaining the ability to reason about components locally, I think that it's easier to work with microservices than monoliths.
> Due to the monolithic software architecture, it was difficult to add new features without affecting the entire system and it was quite complex to release new changes, since we had to rebuild and redeploy the entire product, even though we changed only a few lines of code. That resulted in high risk deployments which happened less frequently - new features got released slowly.
From the article. For a startup the ability to add features quickly is pretty important - especially early on.
I'm not advocating microservices first for every situation, but I've built systems microservice-first and it's been fine.
So we're sending a new data model in the form of JSON over TCP using AMQP? Or are we using STOMP over websockets? Who maintains the broker? Do we use a direct exchange or topic exchange? How do we replicate messages across exchange nodes to ensure uptime? How do we upgrade the broker?
> Shouldn't finger grained scaling be cheaper in some cases?
Monolith, basic high availability is 3 servers, minimum. Now every single microservice needs 3x servers, plus autoscaling, plus we need things like distributed logs, a resilient broker, etc. Even simple things like uptime pinging are more expensive because we're tracking more hosts.
Sure, if you ignore everything outside of your system then it's really easy to work on a single microservice, and if your startup has several million dollars and hundreds of engineers - great, use microservices.
> So we're sending a new data model in the form of JSON over TCP using AMQP? Or are we using STOMP over websockets? Who maintains the broker? Do we use a direct exchange or topic exchange? How do we replicate messages across exchange nodes to ensure uptime? How do we upgrade the broker?
Uh? I don't know? Like, I know how I've done it, idk how you want to do it, and I won't prescribe implementation details as if they're universal.
> Monolith, basic high availability is 3 servers, minimum. Now every single microservice needs 3x servers, plus autoscaling, plus we need things like distributed logs, a resilient broker, etc. Even simple things like uptime pinging are more expensive because we're tracking more hosts.
If you can run your entire project on 3 systems, yeah, sounds like a case where splitting out would be more expensive. Though you can do microservices without having separate hardware - just stick them on the same box. You still get software fault isolation.
> Sure, if you ignore everything outside of your system then it's really easy to work on a single microservice, and if your startup has several million dollars and hundreds of engineers - great, use microservices.
Not disagreeing with the sentiment, but your point about high availability is not entirely accurate. It's 3 'containers' required, meaning that if you were using Kubernetes etc, then you can have multiple services be HA across 3 hosts. Uptime monitoring etc is just config built into the service deployable.
> I find microservices much simpler to reason about.
I don't. Or rather, unlike that of transactional designs used with RDBMs or services deployed into traditional/commercial SOA stacks with distributed transactions, the scope of "reasoning" about microservices is very limited/developer-focused.
But maybe you're using durable queues with exactly-once delivery guarantees, and "idempotent" work requests, which sure is neat if the app is a good fit.
> Otherwise, I find microservices much simpler to reason about.
A counter-argument can be made on this point. You can implement the same isolation levels (modules) but as a monolith using message passing. How is it harder to reason about it then?
In other words, the hard part is how to split your program complexity in modules that are as simple and as orthogonal as possible.
The worse you do this split:
- In a monolithic system, the system becomes exponentially more complex and hard to maintain. You get more bugs, and developers running away from this project as fast as they can, but the thing may fulfill its goals to some degree.
- In a microservice-based system, you may end up either with a handful of huge services (a monolith that uses network-based messages instead of function calls/inproc message passing), or with gross inconsistency problems if you force splits in the wrong places.
Given the operational overhead and that most startups will never get to large scale, I'd say go with the monolith and try to gain traction with your startup. If/when you finally require scale you should have plenty of resources to either split the monolith (if it was well modularized) or just rewrite chunks as services until you get to a fully microservice-based architecture.
Agreed that it is largely about splitting. SOA starts with that premise - but so do actors and modules, without moving out of process, and those are fine approaches too.
Microservice architecture tells you more about how and where to split - introducing bounded contexts and various patterns you might use.
> - In a microservice-based system, you may end up either with a handful of huge services (a monolith that uses network-based messages instead of function calls/inproc message passing), or with gross inconsistency problems if you force splits in the wrong places.
Sure. You can also write really gross, convoluted monoliths.
> Given the operational overhead and that most startups will never get to large scale, I'd say go with the monolith and try to gain traction with your startup.
As the article states, they found that microservices allowed them to move faster on features, which is something that'll matter a lot to a startup. They do, of course, state that there were upfront costs.
> Microservice architecture tells you more about how and where to split
The architecture doesn't tell you anything: it is you who decide how to split. Yes, there are guides and what not to help you make this decision, but again you could do exactly the same splits in a monolithic system.
> Sure. You can also write really gross, convoluted monoliths.
Totally. That's what I was implying when I said "complexity grows exponentially and developers want to run away from the project like hell".
> they found that microservices allowed them to move faster on features
While the article is fine, I don't agree with this affirmation at all. They rewrote the entire system (bit by bit) using better engineering principles, better internal organization, and with a lot of experience about their domain that they didn't have before. As I see it, the outcome you see here is not "microservices!", it is just "doing a better job".
Your viewpoint gives me pause because you aren’t acknowledging the fundamental tradeoffs. Microservices give you flexibility and resiliency but are inherently more complex than the equivalent monolith. Debugging systemic issues across distributed systems is automatically one or more orders of magnitude more difficult.
The elephant in the room is the problem domain. If your domain doesn’t decompose cleanly into services then your base maintenance costs skyrocket. I hate these discussions on HN because there’s so much generalization and opinionated arrogance, when in reality the particulars of a given situation matter far more than high level principles or dev ideology.
> you aren’t acknowledging the fundamental tradeoffs.
Well, the post that I was responding to stated the tradeoffs (complexity). And I was responding by saying that 'complexity' is a bit nebulous - and, in my experience, is reduced in some areas (very easy to reason about independent microservices without having to consider dependencies).
> Debugging systemic issues across distributed systems is automatically one or more orders of magnitude more difficult.
Sure, I guess. I haven't really run into issues that good correlation ids + instrumentation can't help with. Also, I find it really easy to target metrics and 'smoke alerts' to small services. Ideally, in a distributed system, you aren't worrying too much about distributed debugging so much as a single service failure.
> I hate these discussions on HN because there’s so much generalization and opinionated arrogance
Whoof. Let's take a step back here. I shared my experience and opinion, I don't think I'm being arrogant by doing so. I stated that microservice-first is not always the way to go, but that it can work - and I pointed to an area in the article that I thought really highlighted this point (the need to build features rapidly).
I agree with your statements about local reasoning. I do want to call out that micro services also make debugging more complex (in addition to deployment, as you already mentioned). You have to take care to make it possible to stitch together the context in which an error happened. In a monolith, you get this for free with exception stack traces.
You can't make hard rules. Depends on what is being built.
If you're a startup and you can't figure out if you need microservices or not, then hire the right person to make that decision for you. For some it's the right thing, for some it's not.
Actually you can make hard rules. But we should all strive for people to come to good conclusions on their own. The benefits need to justify all the time and energy it takes to do it.
I always tell people that if they can't build a monolith with their team they shouldn't do microservices. Micro-Services are often used as a bandaid over lack of coordination. This works for a little while but once you need a refactor over several services you are in deep trouble.
I've found that there are four main situations where separating functionality out in to a different service works:
* That service would work well enough on its own as a startup - it's internally complicated but isolated and requires a very simple abstraction (e.g. doing a postcode lookup service).
* As a facade to create a clean interface to something that is not clean (e.g. a nice REST API that talks to a crazy weird industrial control system over a parallel port which only runs on windows).
* The operational requirements of the code are entirely different (e.g. moving data processing from the webserver to a task server and feeding it via a queue).
* As a means of linking components in a large scale system run by a large organization that has multiple teams that often write code in different languages and have real trouble coordinating with one another but are nonetheless overseen by a crazy smart architect.
The latter was basically where Martin Fowler thought microservices worked well, and it probably did, but he kind of forgot that A) the absence of a crazy smart architect is more common than the presence and B) this was a hack which involved a shit ton of extra operational overhead that was only worth it because it solved a gnarly people problem.
When startups of 7 people run more than 3 services I start looking for the microservice kool aid.
I'm already seeing the first generation of developers who've only ever worked in an environment that's trying to do microservices and think that the only way of encapsulating code is by making bits of it talk http to other bits.
This. Distributing your components over a network certainly forces encapsulation, but you can have encapsulation without all the complexities that come with running microservices in separate processes / machines.
Why not just choose Akka or Elixir and then you App will be built with message passing from the start. This makes things trivial to break off onto different machines when you need to.
If you choose Elixir you get OTP which does lots of excellent things to be able to scale out your app, the data passing is transparent between nodes (i.e. no protobuf or GRPC here). Excellent ways to monitor and deploy your app (and inspect messages as they are passed). I really need to write up the huge amount of work we’ve put into node and go microservices that are already part of the Erlang/Elixir ecosystem...
For startups don’t bother, if you do it right it will literally kill your startup before you see the benefits.
47 comments
[ 3.4 ms ] story [ 95.2 ms ] threadHow much did the team improve shipping features for customers? Is the app more reliable? Does the engineering team spend way more time on CI/CD and all the other “overhead”?
Most teams will never need this type of solution, even though theyre tons of fun to build and operate. I just wish we had a better way of sharing the non-engineering results of these types of efforts.
CI/CD is required regardless of microservice or monolith. Once you have it working for one deployment, it should be trivial for 1+N.
Maybe you are thinking about how do you deploy inter-service dependencies? In that case, you don't. I'm not joking. When you move to microservices you have to treat other internal services like they are something you do not control. This means maintaining backwards compatibility, versioned APIs, etc...
At first it seems like it is harder, but once you get in the mindset that this always must run and serve existing clients it is rather freeing. Plus, being able to treat each service on its own makes it easy to focus and do large changes - thus move faster.
Compare this to friends who tell me about logging in at 11PM to deploy because they have to take the system down. Completely taking down the system to deploy should almost never happen today.
For a startup - all this may feel OK like you're cheating the system and beating others to the punch - but damn, if you actually make it - good luck scaling that up.
Personally, I don't see faas a competitive market advantage. It's a tool and i'd be a hell of a lot more selective in how I used it.
Why is that a problem? I am speaking in C# terms...
Phase 1 Monolith: all of your code is one solution, with separate domain specific projects (assemblies) with separate namespaces with a logical use of access modifiers exposed as an interface. All of the other code uses interfaces as dependencies defined with a DI framework.
Phase 2: We need scale now. Bring up a lot more VMs at the click of a button behind a load balancer and you get scale quickly.
Phase 3: Take your project that you need to scale independently out of the monolithic solution, expose it as API, put that one API behind a load balancer. Then have a proxy class in your client and use your DI to map your interface to your proxy. If you integrate something like Swagger into your API, it can create the proxy class for you.
If you can deal with eventual consistency, use a queueing mechanism.
Rinse and repeat and keep taking projects out of the monolith as needed.
There will be some shared code you don’t want to run out of process. For that, create Nugget packages and you won’t have to change your client code at all.
Forgive me if my understanding of that architecture is wrong. I only have read parts of the book so far.
It's then mechanically trivial to split the Customer module and the Orders module both the code and the data store.
actually you can keep your solution and just have many projects in one solution (monorepo)
Why? Just because the code sit's in one repo, doesn't mean that everything needs to be deployed the same time.
It's foolish to think that the initial version you make of any system is going to be the same thing that you end up scaling to a million users and it's foolish to think that you're going to understand where your actual pinch points are going to be before that system is under any sort of pressure. Let alone before you really know what your product is really going to be (which is the situation most startups find themselves in).
The slices you decide to make with the knife early on more often than not look stupid and burdensome once you're actually under pressure.
Most people also underestimate how far it's possible to push monoliths. My favourite example is the OpenStreetMap infrastructure, which has to support thousands of concurrent users editing a global map that is ~105G when compressed. It's largely monolithic. And that doesn't really seem to be a problem. Works well.
I suspect most people have never actually seen the sort of "heavy load" they talk about so much running on a sensibly designed monolith to the point that it's not coping due to its architecture. There's a lot of conceit around how big a load people really deal with.
Microservices are great. They are also complex, expensive and require much higher expertise.
Start with a well groomed monolith that is well modularized then split it when scale (user scale, team scale) makes sense.
I would say the complexity is largely in deployment. Otherwise, I find microservices much simpler to reason about.
As an example, keeping a bunch of small, isolated microservices behind queues means that I can reason about them very locally. I know what data they own, I know their interfaces, and I don't really need to think 'outside' fo them - they just send other asynchronous messages out. I don't need to think about dependencies very much - if a downstream or upstream server fails it is irrelevant to the microservices, so long as the queueing system is up.
It's a bit more annoying to get infrastructure and whatnot set up, but not a ton.
> expensive
Maybe? Shouldn't finger grained scaling be cheaper in some cases?
> require much higher expertise
I don't really agree. Again, by keeping things small and by maintaining the ability to reason about components locally, I think that it's easier to work with microservices than monoliths.
> Due to the monolithic software architecture, it was difficult to add new features without affecting the entire system and it was quite complex to release new changes, since we had to rebuild and redeploy the entire product, even though we changed only a few lines of code. That resulted in high risk deployments which happened less frequently - new features got released slowly.
From the article. For a startup the ability to add features quickly is pretty important - especially early on.
I'm not advocating microservices first for every situation, but I've built systems microservice-first and it's been fine.
https://en.wikipedia.org/wiki/Fallacies_of_distributed_compu...
The important part is to get instructure working well first. Things like request-id propagation and good automation of deployment.
As an afterthought, it may bury you, but if you think about those first, then you'll probably gonna have a good time.
> Maybe? Shouldn't finger grained scaling be cheaper in some cases?
While not OP, I'm assuming they think it's more expensive from a development POV, not (necessarily) operationally.
So we're sending a new data model in the form of JSON over TCP using AMQP? Or are we using STOMP over websockets? Who maintains the broker? Do we use a direct exchange or topic exchange? How do we replicate messages across exchange nodes to ensure uptime? How do we upgrade the broker?
> Shouldn't finger grained scaling be cheaper in some cases?
Monolith, basic high availability is 3 servers, minimum. Now every single microservice needs 3x servers, plus autoscaling, plus we need things like distributed logs, a resilient broker, etc. Even simple things like uptime pinging are more expensive because we're tracking more hosts.
Sure, if you ignore everything outside of your system then it's really easy to work on a single microservice, and if your startup has several million dollars and hundreds of engineers - great, use microservices.
Uh? I don't know? Like, I know how I've done it, idk how you want to do it, and I won't prescribe implementation details as if they're universal.
> Monolith, basic high availability is 3 servers, minimum. Now every single microservice needs 3x servers, plus autoscaling, plus we need things like distributed logs, a resilient broker, etc. Even simple things like uptime pinging are more expensive because we're tracking more hosts.
If you can run your entire project on 3 systems, yeah, sounds like a case where splitting out would be more expensive. Though you can do microservices without having separate hardware - just stick them on the same box. You still get software fault isolation.
> Sure, if you ignore everything outside of your system then it's really easy to work on a single microservice, and if your startup has several million dollars and hundreds of engineers - great, use microservices.
That seems like an exaggeration.
I don't. Or rather, unlike that of transactional designs used with RDBMs or services deployed into traditional/commercial SOA stacks with distributed transactions, the scope of "reasoning" about microservices is very limited/developer-focused.
But maybe you're using durable queues with exactly-once delivery guarantees, and "idempotent" work requests, which sure is neat if the app is a good fit.
A counter-argument can be made on this point. You can implement the same isolation levels (modules) but as a monolith using message passing. How is it harder to reason about it then?
In other words, the hard part is how to split your program complexity in modules that are as simple and as orthogonal as possible.
The worse you do this split:
- In a monolithic system, the system becomes exponentially more complex and hard to maintain. You get more bugs, and developers running away from this project as fast as they can, but the thing may fulfill its goals to some degree.
- In a microservice-based system, you may end up either with a handful of huge services (a monolith that uses network-based messages instead of function calls/inproc message passing), or with gross inconsistency problems if you force splits in the wrong places.
Given the operational overhead and that most startups will never get to large scale, I'd say go with the monolith and try to gain traction with your startup. If/when you finally require scale you should have plenty of resources to either split the monolith (if it was well modularized) or just rewrite chunks as services until you get to a fully microservice-based architecture.
Microservice architecture tells you more about how and where to split - introducing bounded contexts and various patterns you might use.
> - In a microservice-based system, you may end up either with a handful of huge services (a monolith that uses network-based messages instead of function calls/inproc message passing), or with gross inconsistency problems if you force splits in the wrong places.
Sure. You can also write really gross, convoluted monoliths.
> Given the operational overhead and that most startups will never get to large scale, I'd say go with the monolith and try to gain traction with your startup.
As the article states, they found that microservices allowed them to move faster on features, which is something that'll matter a lot to a startup. They do, of course, state that there were upfront costs.
The architecture doesn't tell you anything: it is you who decide how to split. Yes, there are guides and what not to help you make this decision, but again you could do exactly the same splits in a monolithic system.
> Sure. You can also write really gross, convoluted monoliths.
Totally. That's what I was implying when I said "complexity grows exponentially and developers want to run away from the project like hell".
> they found that microservices allowed them to move faster on features
While the article is fine, I don't agree with this affirmation at all. They rewrote the entire system (bit by bit) using better engineering principles, better internal organization, and with a lot of experience about their domain that they didn't have before. As I see it, the outcome you see here is not "microservices!", it is just "doing a better job".
I don't really agree. The major difference between SOA and Microservice is the guiding principals, such as the bounded context.
> As I see it, the outcome you see here is not "microservices!", it is just "doing a better job".
Maybe so.
The elephant in the room is the problem domain. If your domain doesn’t decompose cleanly into services then your base maintenance costs skyrocket. I hate these discussions on HN because there’s so much generalization and opinionated arrogance, when in reality the particulars of a given situation matter far more than high level principles or dev ideology.
Well, the post that I was responding to stated the tradeoffs (complexity). And I was responding by saying that 'complexity' is a bit nebulous - and, in my experience, is reduced in some areas (very easy to reason about independent microservices without having to consider dependencies).
> Debugging systemic issues across distributed systems is automatically one or more orders of magnitude more difficult.
Sure, I guess. I haven't really run into issues that good correlation ids + instrumentation can't help with. Also, I find it really easy to target metrics and 'smoke alerts' to small services. Ideally, in a distributed system, you aren't worrying too much about distributed debugging so much as a single service failure.
> I hate these discussions on HN because there’s so much generalization and opinionated arrogance
Whoof. Let's take a step back here. I shared my experience and opinion, I don't think I'm being arrogant by doing so. I stated that microservice-first is not always the way to go, but that it can work - and I pointed to an area in the article that I thought really highlighted this point (the need to build features rapidly).
Yeah, sure, knives are useful and you can always find exceptions for a few 2 years old.
But still. Pretty good rule.
* That service would work well enough on its own as a startup - it's internally complicated but isolated and requires a very simple abstraction (e.g. doing a postcode lookup service).
* As a facade to create a clean interface to something that is not clean (e.g. a nice REST API that talks to a crazy weird industrial control system over a parallel port which only runs on windows).
* The operational requirements of the code are entirely different (e.g. moving data processing from the webserver to a task server and feeding it via a queue).
* As a means of linking components in a large scale system run by a large organization that has multiple teams that often write code in different languages and have real trouble coordinating with one another but are nonetheless overseen by a crazy smart architect.
The latter was basically where Martin Fowler thought microservices worked well, and it probably did, but he kind of forgot that A) the absence of a crazy smart architect is more common than the presence and B) this was a hack which involved a shit ton of extra operational overhead that was only worth it because it solved a gnarly people problem.
When startups of 7 people run more than 3 services I start looking for the microservice kool aid.
Like staticassertion already mentioned, it depends on the real project and problem to solve.
I've pitched a startup which started directly with an microservice like architecture. It was the best possible approach for the given problem.
If you choose Elixir you get OTP which does lots of excellent things to be able to scale out your app, the data passing is transparent between nodes (i.e. no protobuf or GRPC here). Excellent ways to monitor and deploy your app (and inspect messages as they are passed). I really need to write up the huge amount of work we’ve put into node and go microservices that are already part of the Erlang/Elixir ecosystem...
For startups don’t bother, if you do it right it will literally kill your startup before you see the benefits.