
What to automate first in a small business
Choose a first automation by scoring the work, data, risk, ownership, and reversibility. Then validate one pilot before you expand it.

The monolith versus microservices debate is often framed as a choice between old and modern. That framing is unhelpful. Architecture should fit how a team develops, releases, and operates a product. Every service boundary creates independence, but it also introduces a network, another deployment, and more places where a request can fail.
A modular monolith runs as one application while separating its internals by business capability. Orders, billing, and inventory expose owned interfaces instead of reaching into each other's tables. Microservices move comparable boundaries into separate processes and usually separate data stores. The important difference is the operating cost of the boundary, not the number of repositories.
Same domain, two operational price tags
Boundaries can be identical. The difference is process, network, and ownership.
Modular monolith
One process and deployment. Modules communicate through internal contracts.
Microservices
Independent processes and deployments. Every boundary adds network and operations.
If a team cannot draw a useful domain boundary inside one process, a network will not discover it. An uncertain split becomes frequent remote calls, shared tables, and releases that still need coordination. The result has distributed failure modes without genuine independence.
A module needs a public contract. Billing code should not read inventory internals. It requests a reservation through an interface owned by the inventory module. Dependency rules and architecture tests can keep that boundary honest. Once the local contract is stable, moving it behind an API is far less risky.
Useful modules follow business capabilities rather than technical layers such as controllers and repositories. A pricing change then remains inside pricing instead of leaking into shipping. The same principle appears at code level in our guide to design patterns in practice.
An independently deployed service can change on its own cadence. Search can ship without releasing the full product. A compute-heavy workload can scale separately, and a sensitive capability may have a stricter security boundary. Independence is valuable when an organisation can actually use it.
The bill arrives immediately. A function call becomes a network request. It may be slow, duplicated, or unavailable. The system needs timeouts, idempotent retry behaviour, traceable requests, and a plan for partial failure. One database transaction can no longer hold an entire business operation together.
Testing changes too. A passing unit test does not prove that deployed services still agree. Consumer and provider contracts need compatibility checks. Production needs logs, metrics, and traces that reveal where a request stopped. Without those abilities, diagnosis time can grow faster than the service count.
A service that owns code but queries another service's tables is not independent. A schema change can break it without touching its repository. Data ownership is therefore part of the architecture, not a later storage concern.
Separate stores also mean that some views are temporarily stale. An order may be accepted before billing consumes the event. The team must decide where that delay is safe. An account balance or reservation of the final item may need a different consistency model from a reporting dashboard.
A distributed transaction should not be disguised as a fragile chain of synchronous calls. Events, idempotent consumers, and recoverable workflows can help. They are also more machinery to monitor and test. Where the product does not require independent data ownership, one database protected by module boundaries is usually cheaper.
Microservices work best when teams can own a service from design through production incidents. A separate repository with no stable owner spreads responsibility rather than clarifying it. Changes wait for people who understand another link in the chain.
A smaller product team often gains more from one deployment, one development environment, and direct refactoring across modules. That does not require a tangled monolith. It means distribution is an expensive way to enforce code discipline.
The balance shifts when independent teams repeatedly block one release, the domain boundary is stable, and each area needs its own operating cadence. Extraction may then reduce coordination. The evidence comes from work already happening, not a fashionable reference diagram.
Signals that a module has outgrown one deployment
Split for a measured problem, not an imagined future scale.
Independent change cadence
One module blocks releases of the rest.
Different scaling profile
Load is isolated and repeatedly measured.
Clear owner
A team can own delivery and operations.
Stable contract
The domain boundary no longer moves every sprint.
One signal is an independent reason to change. The module has its own roadmap and most of its work does not require edits elsewhere. Another is an operating difference. It needs distinct scaling, availability, or a technology that the rest of the application does not need.
A stable contract is equally important. The team can name inputs, outputs, data ownership, and failure behaviour. If the contract changes every sprint, independent deployment merely turns local instability into API versioning work.
A practical route is to harden the boundary in the monolith first. Remove direct database shortcuts, add contract tests, and measure interactions. Then compare the benefit of extraction with the price of distribution. The service is a conclusion supported by evidence.
For a new business system, a modular monolith is often a sensible starting point while the product and boundaries are still changing. One deployment keeps feedback fast. Strong modules preserve the option to extract the capability that later earns independence.
Microservices are appropriate when the company already pays a measurable price for shared releases, shared scaling, or unclear ownership. The estimate must include the platform, observability, and incident response. Splitting source code alone creates none of those capabilities.
In custom software development, we record these assumptions as a decision that can be reviewed. If an existing system already makes change dangerous, the next article covers legacy modernization without a big-bang rewrite. The goal is not to win an architecture argument. It is to lower the cost of safe change.
Maroš Bednár prepared the article with AI support for research and language editing. He reviewed and approved the technical conclusions, examples, and final text.

Choose a first automation by scoring the work, data, risk, ownership, and reversibility. Then validate one pilot before you expand it.
Companies either ignore AI or try to change everything at once. Both are wrong. Here's a realistic 30-day plan.

Replace risky parts of an older system in controlled stages. Learn how seams, a facade, contract tests, parallel runs, and rollback turn modernization into managed delivery.