This sounds like it could work, but then you start to wonder about how you'd get common code into those 12 services. Our answer at the time was nugets, but we operate in a sensitive domain with proprietary code, so public nuget services were a no go. So, we stood up our own goddamn nuget server just so we could distribute our own stuff to ourselves in the most complicated way possible.
Even if you are using all the same language and patterns everywhere, it still will not spare you from all of the accidental complexity that otherwise becomes essential if you break the solution into arbitrary piles.
One is much simpler than the other. Artifact management is surprisingly complex, it only looks like it works great while you aren't managing many versions and acting more like a monolith, just spread across repos/deploy points.
You already have that pipeline for release/deployment though, don't you? (And it's already hooked up to your SSO or what have you).
> if you have three projects in three checkouts that all have to be coordinated and merged in order so that you don't accidentally break your environment and worry about security and and and....
It's the same as any other library dependency though, which is a completely normal thing to deal with. The cost of separating your pieces enough that you can use different versions of a library in different services is that you can use different versions of a library in different services.
I'm skeptical about microservices as a deployment model, but I'm absolutely convinced that code-level modularisation and independent release cycles for things that deploy independently are worthwhile, at least if your language ecosystem has decent dependency management.
Nuget does provide mechanisms for obsoleting packages, so it's reasonable to enforce that new packages should allow for a few versions worth of backwards compatibility before deprecation and finally pulling the plug.
One of my problems with microservices isn't really the services themselves, but the insane amount of tooling that creeps in: GRPC, Kafka, custom JSON APIs, protobufs, etc. etc. and a lot of them exist in some form to communicate between services.
I'm gonna have to disagree with this. Often when languages add features to their core, it allows for a very different (and often better) approach to writing code. Think Lisp with first class functions, or Rust with the borrow checker. Why should concurrency be any different? This feels like a Blub moment and I would highly recommend you give erlang or elixir a try, just to see what it is about.
If your typical microservice setup is simply distributing your call stack over a network (and oftentimes that's all it is), then you might as well use a language designed to operate in such a manner and reap the benefits of it. That kind of microservice architecture only really exists as a function of the organisation's structure such that teams can work more autonomously.
Been free in my IDE since I compiled the code...
"E2E integration tests"
I can mostly run these on my machine, no need to stand up a cluster to get it running (bonus points if you virt multiple machines on one and still don't need the cluster for complex distributed scenarios).
"you will need some other kind of persistent message queue"
var queue = new Queue(); // then sometime later... queue.Save(); // or queue.EmplaceAndSave(); ... queue.Pop();
Trivial and didn't need a server to set it up.
Lots of tech stack stuff simply disappears without server boundaries and the like to get in the way. There is other tech you have to deal with, but at the small scales it mostly doesn't apply. Which, you as a dev are usually only working at small, testing scales, so you don't usually need to support it.
Yeah, no... you'll lose data for sure, you'll have race conditions or no cooperative queuing between multiple instances of the application. This is exactly the kind of half-assery that people resort to when they say monoliths are so much less complex than microservices. A good monolith still requires all the same hard decisions about modularity, high-availability etc.
Default queue implementations come with co-operating queuing out of the box. I suppose you could use some hand-rolled queue with no internal locking, but this is disingenuous.
> you'll have race conditions or no cooperative queuing between multiple instances of the application.
You're thinking micro-service again here. There's no need to have multiple "instances" at all. Any concurrency is handled internal to the application itself with use of e.g. fibers, threads, etc. A good argument to why monoliths have drawbacks can't be "well its not a microservice". :)
> A good monolith still requires all the same hard decisions about modularity, high-availability etc.
Never said it didn't. What it doesn't require is all the tech stack to support that over many instances, because there's one instance. A large majority of µServices is just re-implementing what your runtime gives you for free.
Too often devs weaponise micro services and say it’s one of the key reasons for microservices is to allow free language choice !