@JussiMannisto the only way to truly decouple services, i.e. to satisfy your 3 points, is to make them communicate asynchronously.
Say, you have a monolith that have something like this:
$product = $this->productService->getProductBySomeCondition(.....);
$isProductAvailable = $this->inventoryService->checkAvailability($product->id);
you decide to split the Inventory part and the metadata part to "independent" services:
$product = $this->productClient->get('/details', [ 'conditions' => [....] ]);
$isProductAvailable = $this->inventoryClient->get("/product/availability/{$id}");
Now the Product Api is a whole different codebase and Inventory Api is a whole different codebase. We have achieve microservices, right? nope.
All the services is dependent on each other.
What if /details changes the response data? what if it change the parameter?
What if one of these service are down? what if multiple services are down?
The answer is simple: the whole system fail.
Look: Any business changes will require redeployment of ALL of the involved services. Imagine you have 10 services calling the Product microservices. Now the business changes and the data of a product have an additional 5 fields. What happen then? All 10 services must adjust their code and redeploy, no?
No:
- Is developed and deployed independently.
not possible with synchronous communication. Changes incur redeploy on all fronts
- Is autonomous and loosely coupled.
not possible with synchronous communication. Even if you do fire-and-forget, services must at least know: auth, endpoint, and input parameter of each other. Not "loosely coupled"
- Has a small and specific role.
As soon as a service call another. They are dependent on that service and inflate their role.
Why would using HTTP make an architecture monolithic
Why would asynchronous messaging make it suddenly not monolithic
Say, you have 10 services. 9 crashed for 1 hour. Can you make sure that in this 1 hour, all requests to that 1 living service succeed. And, after that 1 hour, after the other 9 come back up, they all receive their appropriate "notification" and process all the data they missed in that 1 hour? With just HTTP?
You can with the outbox pattern with a persistent message broker. Btw it is one of the application of the "eventual consistency" concept
The whole point of a microservices system is that each microservice doesnt even know about each other, even their existence. HTTP request by definition need the caller to know about the called's existence so that's a big difference. The services publish an event, or "announce" the something has been done, to a central dashboard, in this case, a message broker. Every other service can access this "dashboard" and decide if they need to do something based on stuffs posted on there. The one who publish it, however, does not care if who, or anyone do what, or not do what, in reaction to what they posted.
What this achieve is each services is truly coupled. They dont need to know or care about any other service, they had only 2 jobs: do their task, and publish the event after that task is done. Every other service can crash and burn and disappear, doesnt matter (to that service). Every other service can update specs, can rebuilt their service from scratch, can change server, change domain, change framework, change language, reconstruct their whole database,... and it doesnt affect your service in the slightest
if you want to learn more, there's this comment that can give more direction on the various concepts of Service-Oriented Architecture (SoA), microservices, event-driven architecture,....