Architecture is a consequence of constraints

The monolith-versus-microservices debate is often framed as a contest between old and modern architecture. That framing is not useful. Both models can support excellent systems, and both can produce expensive failures. The better question is: which set of constraints do you want to pay for now?

A monolith concentrates complexity inside one deployable system. Microservices distribute complexity across network boundaries, deployment units, data ownership, observability, and operations. The second model can create powerful organisational and technical independence, but that independence is not free.

When we make the decision, we start with the organisation and the domain before touching the infrastructure diagram.

Question 1: how many teams need independent ownership?

A team of five engineers rarely needs twenty independently deployable services. The coordination cost inside one small team is usually lower than the operational cost of distributed architecture. A modular monolith can provide strong internal boundaries while preserving simple local development, testing, deployment, and debugging.

The argument for services becomes stronger when multiple teams need to change different parts of the product without blocking one another. If one group owns billing, another owns identity, and another owns a high-volume processing domain, independent deployment and ownership can reduce coordination overhead.

We look for durable team boundaries, not an org chart that may change next quarter. Architecture built around temporary reporting lines ages badly.

Question 2: are the domain boundaries actually clear?

Microservices work best when the business domain contains meaningful boundaries that can own behaviour and data. If the team cannot explain what a service is responsible for without using phrases like “shared stuff” or “common data,” the boundary is probably premature.

A useful service boundary should minimise chatty cross-service coordination. If completing one user action requires synchronous calls across six services and a distributed transaction to keep them consistent, the architecture may have split the system along technical layers instead of business capabilities.

When domain understanding is still evolving, a modular monolith often gives the team room to learn. Boundaries can be enforced in code first and extracted later when the evidence is stronger.

Question 3: what release independence do you genuinely need?

Microservices are valuable when independent release cadence matters. A risk-scoring component may need daily changes while a regulated ledger changes rarely. A high-traffic API may require rapid performance tuning without redeploying an unrelated administration interface.

But independent deployment only matters if teams can actually use it. If every service release still requires a coordinated platform window, shared database migration, or full-system regression cycle, the system has paid for microservices without receiving much autonomy.

We examine the current bottleneck. If releases are slow because tests are weak or environments are unreliable, splitting the application will not solve the underlying delivery problem.

Question 4: does one workload need a different scaling model?

Uneven scaling can justify separation. A document-processing pipeline may require large bursts of compute while the rest of the application serves ordinary transactional traffic. A real-time ingestion service may have very different availability and throughput requirements from internal reporting.

However, cloud platforms make it possible to scale many monolithic workloads much further than teams assume. “We might need to scale” is not sufficient justification for distributed architecture. We want evidence that one part of the system has materially different resource, latency, isolation, or availability requirements.

Scale is multidimensional. Request volume, data volume, concurrency, geographic distribution, and organisational scale may point to different architectural answers.

Question 5: how mature are your operations?

Microservices move failure from inside a process to across a network. That introduces timeouts, retries, partial failure, idempotency, queue semantics, service discovery, version compatibility, tracing, and more complex incident response. None of these are impossible, but they must be owned.

Before recommending microservices, we ask whether the organization has reliable CI/CD, centralized logging, metrics, tracing or equivalent request correlation, infrastructure & ongoing support, secret management, service ownership, and an on-call model capable of diagnosing cross-service failures.

If the answer is no, a distributed architecture can overwhelm a team that is still learning to operate one production system well.

Question 6: do compliance or isolation requirements force separation?

Sometimes architecture is constrained by security, data residency, or regulatory boundaries. A workload containing highly sensitive data may need stronger network, account, region, or operational isolation. Different customer segments may require distinct deployment models. A service that touches payment data may warrant a smaller compliance scope than the rest of the platform.

These are legitimate reasons to separate components, but the separation should follow the control boundary. Splitting everything into services does not automatically improve security. In fact, it can increase IAM complexity, secret distribution, and attack surface if designed carelessly.

We prefer the minimum boundary that satisfies the requirement and remains operable.

Question 7: what kind of consistency does the product require?

Inside a monolith with one transactional database, strong consistency is comparatively straightforward. Across services, workflows often become eventually consistent. That can be completely acceptable, but product behaviour must tolerate it.

If a business operation must atomically update inventory, billing, entitlement, and compliance state, distributing those responsibilities creates coordination challenges. Patterns such as sagas and outboxes help, but they add complexity that needs to be justified by other benefits.

We ask product stakeholders what temporary inconsistency means in user terms. Architecture decisions become clearer when translated into visible behaviour rather than abstract CAP-theorem discussions.

Our default starting point: a modular monolith

For many new B2B products, our default is a well-structured modular monolith. That does not mean one unbounded codebase with everything coupled to everything else. It means one deployable application organised around explicit domains, controlled dependencies, clear interfaces, and data ownership conventions.

This structure keeps local development simple and transactions straightforward while preserving the option to extract services later. It also forces the team to solve the hardest problem first: defining boundaries. If those boundaries cannot survive inside one codebase, putting HTTP between them will not magically improve the design.

A modular monolith is often the fastest route to evidence.

When we would actively choose microservices

We become more confident in microservices when several conditions appear together: multiple autonomous teams, stable domain boundaries, different scaling or reliability profiles, a genuine need for independent deployment, and operational systems mature enough to support distributed ownership.

We also prefer selective decomposition. A product does not need to become “microservices architecture” in one migration. A high-volume ingestion pipeline, identity boundary, billing platform, or compute-heavy subsystem can be separated while the rest remains consolidated.

The goal is not architectural purity. It is to put complexity where it creates leverage.

The decision in one sentence

Choose the simplest architecture that supports the organisation you have, the domain you understand, and the operational guarantees you actually need - while leaving a credible path to evolve when those constraints change.

If the case for microservices depends mostly on hypothetical future scale, we usually wait. If the case is driven by present team autonomy, stable boundaries, differentiated workloads, or hard isolation requirements, services may be the right trade.

Architecture should reduce the cost of change. The moment it becomes a status symbol, the decision framework has already failed.