# Before You Split Your .NET Application Into Microservices, Define the Problem

Microservices are attractive for good reasons. They can let teams deploy business capabilities independently and scale individual services according to demand.

But those benefits come with responsibilities: managing service contracts, coordinating interactions, and maintaining multiple application lifecycles. Moving to microservices changes where complexity lives; it does not make complexity disappear.

Before discussing service boundaries, deployment platforms, or messaging infrastructure, start with a simpler question:

What problem are we trying to solve?

### A growing codebase is not a complete diagnosis

“The application is getting large” describes a symptom. It does not explain what is preventing the team from delivering.

A more useful diagnosis might be:

- Changes to one business area repeatedly require changes in unrelated areas.
- One workload needs substantially different scaling from the rest.
- Teams cannot release their work without coordinating a shared deployment.
- Ownership of business rules is unclear.

These are different problems. They should not automatically receive the same architectural solution.

Microservices are particularly relevant when independently deployable business capabilities address a real delivery or scaling constraint. Microsoft’s architectural guidance places that autonomy—not simply smaller codebases—at the centre of the approach.

### Think in business capabilities, not technical layers

Consider an illustrative lending application with four responsibilities:

- Loan applications.
- Eligibility assessment.
- Disbursements.
- Notifications.

One possible starting point is a single .NET application organised into explicit modules:

```text
src/
  Lending.Api/
  Modules/
    Applications/
    Eligibility/
    Disbursements/
    Notifications/
```

This structure is an example, not a complete architectural prescription.

Its purpose is to make the business responsibilities visible before deciding which ones need separate deployment.

Contrast that with creating a “controller service,” a “business logic service,” and a “database service.” Those boundaries follow technical layers rather than complete business capabilities.

Microsoft describes microservices as autonomous components that encapsulate business capabilities, bringing the relevant layers together within each service boundary.

The important design question becomes:

What does this capability own, and what must other capabilities know about it?

### Make the reason for extraction explicit

Suppose the notification workload grows substantially while the application-processing workload remains stable.

That might justify investigating a separate notification service.

But the proposal should explain more than “notifications are a separate module.” It should establish:

1. What limitation exists today.
2. How independent deployment or scaling would address it.
3. What interface the extracted service would expose.
4. Who would own its operation.
5. How the team would determine whether the extraction helped.

This turns an architectural preference into a testable engineering decision.

Service isolation is valuable when a service can genuinely be deployed and scaled independently. Microsoft’s modernisation guidance explicitly identifies that isolation as a design objective.

### Include operations in the design

A service boundary is also an operational commitment.

Before extracting a capability, work through questions such as:

- Who owns its deployment pipeline?
- How will callers handle an unavailable service?
- How will interface changes be coordinated?
- Which logs and metrics will reveal a problem?
- How will the team trace a request across service boundaries?

These questions belong in the design discussion, not only in the incident review.

Microsoft’s guidance for rebuilding applications with microservices includes logging, monitoring, and tracing alongside service isolation. The operational model is part of the architecture.

### Migrate deliberately, not all at once

A useful migration proposal can focus on one capability rather than a complete rewrite:

1. Identify the capability and its dependencies.
2. Define the boundary and the expected benefit.
3. Extract it incrementally while maintaining service continuity.
4. Measure whether the original constraint has improved.

That approach aligns with Microsoft’s recommendation to assess dependencies, identify bounded contexts, and incrementally move capabilities into services. A bounded context is an explicit boundary within which a particular domain model applies.

For the illustrative lending platform, the first extraction does not have to establish the final architecture of every other module. It only needs a defensible purpose and a boundary the team can operate.

### Use an extraction checklist

Before approving a new service, complete this sentence:

“We are extracting this capability because \_\_\_\_\_, and we will know the change helped when \_\_\_\_\_.”

Then check whether the proposal includes:

- A clear business responsibility.
- A concrete need for independent deployment or scaling.
- Defined interfaces and dependencies.
- Named operational ownership.
- A measurable outcome.

If those answers remain vague, spend more time understanding the problem before adding another service.
