Just like I can't understand how people can come up with the right tests before the code in TDD, I can't understand how people can come up with the right microservices before they start developing the solution.
Just like I can't understand how people can come up with the right tests before the code in TDD, I can't understand how people can come up with the right microservices before they start developing the solution.
Not doing this runs the risk of testing what you did, not testing that it's right. You can get lucky, and do it right the first time. Or you can make a bunch of tests that test to make sure nothing changed, with no eye as to whether it's what anybody actually wanted in the first place.
Sitting down with somebody for whom TDD is natural is educational and makes it very hard to argue against it, particularly for library code.
You end up testing that numbers came out of a function or that some thing was called, but it doesn't actually solve the real issue which is to get your use cases correct. Instead it encourages you to break down the problem into a bunch of unrelated bits, it doesn't actually check that your approach is correct or what the customer wants, just that you wrote some bits of code which do things, whether those things are the right things...
As it is often practiced it is usually a failsafe for people who struggle to write code at all.
Acceptance tests are too happy pathy, integration tests are rarely done or deemed 'unnecessary', so the only place left to 'think about the problem' becomes actually writing/designing the code. And so tests tend to come last, because you already decided what works, and they check nonsense.
For truly difficult code, such as a mathematical algorithm which is difficult to break down, unit tests make sense, the majority of "when X is true do A, when X is false do B" of unit tests are utter garbage.
I'm stealing that. I have seen soo many small projects crumble due to sheer unnecessary complexity introduced by modularization dogmas.
Likewise, with a microservice architecture, you have requirements that define a set of data C that must be available for an application that provides get/post/put/delete/events in a set B to your service over a transport protocol. You need to provide access to this data via the same transport protocol, transform the input protocol to a specified output protocol.
You also have operational concerns, like logging that takes messages in a set C and stores them. And monitoring, and authorization, etc. These are present in every request/response cycle.
So, you now split the application into request/response services across the routing boundary-> 1 route = 1 backing model. That service can call other apis as needed. And that's it. It's not hard. It's not even module-level split depolyment. It's function-level deployment in most serverless architectures that is recommended because it offers the most isolation, while combining services makes deployment easier, that's mostly a case of splitting deployment across several deployment templates that are all alike and can be managed as sets by deployment technologies like Cloudformation and Terraform [1].
You can also think of boundaries like this: services in any SOA are just like software modules in any program - they should obey open/closed and have strong cohesion [2] to belong in a singular deployment service.
Then you measure and monitor. If two services always scale together, and mutually call each other, it's likely that they are actually one module and you won't effect cohesion by deploying them as a single service to replace the two existing ones. easing ops overhead.
Not deploying and running as a monolith doesn't mean not putting the code to be run into the same scm/multiproject build as a monorepo for easy shared cross-service message schema refactoring, dependency management, and version ingredient. That comes with its own set of problems -- service projects within the repo that do not change or use new portions of the comm message message schema shouldn't redeploy with new shared artifact dependencies; basically everything should still deploy incrementally and independently, scaling it is hard (see Alphabet/Google's or Twitter's monorepo management practices, for example); but there seems to be an extra scale rank beyond Enterprise size that applies to, it's very unlikely you are in that category, and if you are you'll know it immediately.
We like to market microservice architecture as an engineering concern. But it's really about ops costs in the end. Lambdas for services that aren't constantly active tend to cost less than containers/vps/compute instances.
1: http://serverless.com//blog/serverless-architecture-code-pat...
2: http://www.cs.sjsu.edu/faculty/pearce/modules/lectures/ood/m...