. Geolocation Dependency
For example, you have a task to collect data from your client's devices, but these devices are located within the internal network of a specific warehouse. In this case, you would allocate a separate microservice that will reside on a server within that warehouse and communicate with it via a transport layer.
The same applies if you need to deploy a service only within one of the regions (e.g., only RU or EU); then you can create a separate module solely for that region.
. Stateful
For instance, you need to maintain open Web Socket or TCP connections, and you want to redeploy and generally touch this application as little as possible for maximum uptime. In this scenario, you would allocate a separate microservice/module that will store the state (sockets) and communicate with it via a transport layer.
. Separate Feature Set
Your partners require a stripped-down/different variation of your main API. In this case, you would create a separate module where you expose only what's necessary, plus replace the authentication method (e.g., with oAuth), and so on.
. Dedicated Resources
Your application requires extensive file system operations, or, for example, image compression, streaming video processing, or CPU-intensive calculations – in short, something that demands specific resources. Then, you would allocate a microservice/module and deploy it on machines with the necessary resources.
. Interfering with Others
A particular endpoint is exceptionally busy (e.g., you collect every click from a client's browser), and it generates too much traffic, the processing of which interferes with the processing of other requests.
In this situation, you can isolate precisely this piece into a separate module/microservice and deploy it on a separate machine.
. Independent Deployment
**When we want different services to be deployable independently of each other (e.g., so that a redeploy doesn't affect applications whose code hasn't been changed in a PR).
Then you can allocate a module (modules have their own independent Docker images, so after building, you can check if the hash has changed to decide on a redeploy) or a microservice.
. Independent Business Logic
**This is the MOST complex aspect because the independence of one microservice from another is often a temporary concept (remember that requirements always change). However, if one module is truly capable of operating independently of another (e.g., a reward calculation system and an authentication system), then it's a candidate for extraction into a microservice.
BUT I recommend doing this as a second step, after you've realized that these modules have genuinely become independent of each other and for the convenience of further development, you want to separate the codebases.
ONCE AGAIN, only time will reveal the true independence of codebases.
Summary
I'm sure I've missed other valid reasons for dividing applications into modules and microservices, so please share them in the comments.