A lightning talk

Start Boring. Scale Deliberately.

My take on monoliths, microservices, and the agentic world.

Ink and watercolor sketch of a lone paddler steering a small boat down a fast river between stone buildings
The world has changed

Good design hasn't.

AI coding agents are doing real work in real codebases. And it turns out they're remarkably good at it, when they can see the whole picture. The thing that's good for junior engineers is also good for AI agents: being able to see the whole codebase without filing a ticket to another team.

The smart default

Monorepo. Monolith.

Monorepo

Shared types. Visible contracts. Cross-cutting call sites. Refactor across domain boundaries in a single PR. Your agents, and your humans, can see everything.

Monolith

Function calls instead of network hops. A single deployment surface. “What does this change affect?” is still an answerable question. Better yet, make it modular. More on that below.

Starting here isn't naive. It's the choice that keeps your options open.

The three forces

What's actually pushing your architectural decisions.

Conway's Law

Your org chart is quietly writing your architecture. Siloed teams build hard walls. If your microservices diagram looks like your reporting structure, that's not a coincidence. It's causation. Reorganize first, then decide.

Legacy headwind

Every historical decision is a current pushing against you. The temptation is to escape it by starting something new alongside the old. Usually you're not escaping the mess. You're duplicating it.

Greenfield temptation

“What if we just extracted this one piece and did it right?” This is how most premature extractions start: a service spun up to escape technical debt, not because the physics demanded it. The new thing feels clean until it has to talk to the old thing.

Three questions teams conflate

A microservice is not a domain boundary.

Treating a microservice as the way you express a domain boundary is a shortcut. These are three separate problems.

Where does your code live?

Monorepo vs. polyrepo. A collaboration and context decision.

How is your code deployed?

Monolith vs. microservices. A deployment and scaling decision.

Where are your domain boundaries?

A design decision. Enforceable inside a monolith.

Softer tools first

You don't need a network call to draw a boundary.

Before you pay the deployment tax, ask whether softer tools get you 80% of the discipline.

Package structure

Module-level isolation.

Ownership files

CODEOWNERS and team accountability.

Import constraints

Explicit rules on who talks to whom.

Code review conventions

Human enforcement of domain boundaries.

Separate deployment is the strongest enforcement, and the most expensive. Match your enforcement to your actual problem.

The missing middle ground

The modular monolith.

A modular monolith lets an organization keep things simple while it scales. It is the pragmatic alternative to distributed microservices.

Codex-style ink sketch of one large building, cut away to show separate chambers under a single roof

Shopify

With 2.8 million lines of Ruby, Shopify explicitly chose a modular monolith to handle Black Friday at global scale.

Stripe

Powering hundreds of billions in payments with over 20 million lines of Ruby, Stripe continues to operate as a successful monolith.

Uber

After scaling to 4,500 microservices, dubbed the “Death Star” by engineers, Uber is now consolidating back to “macroservices.” That is the complexity cost.

“Don't start a new project with microservices, even if you're sure your application will be big enough to make it worthwhile.”

Martin Fowler
When you earn the extraction

The bar should be high.

Microservices become the right answer only when a piece of your system has genuinely different physics.

A different scaling law

40 GPU instances and two t3.mediums aren't the same problem.

A different availability SLA

That seam is real. The physics demand a hard wall.

Different team ownership

A genuine need for autonomy, not just a preference.

That's surgery with a clear indication, not architecture for architecture's sake.

The distributed systems tax

Every extraction is a CAP theorem decision.

You're making it at the architecture level, and this is what you pay.

Network latency

Where you once had a function call.

Distributed failure modes

Partial outages, retry storms, cascading failures.

Versioned contracts

APIs that must be maintained across independent release cycles.

Harder observability

Traces span processes and logs need correlation. Context windows shrink for your agents, and your AI tooling loses the picture entirely.

Navigate the current

Don't fight it.

The paddler doesn't fight every current. They read the water, use force deliberately, and correct only when the physics demand it. Your monolith is the boat. Your service boundaries are reading the current correctly. Extraction is a correction maneuver: precise, intentional, earned.

Microservices solve scaling problems. Monorepos solve collaboration problems. Service boundaries solve design problems. Know which problem you actually have. Don't pay the distributed systems tax until the scaling math forces your hand.

Worth arguing about

Five questions to take back to your team.

  1. Should the CTO be making this decision? Or is this an engineering leadership decision that CTOs often wrongly grab? What's the right level?
  2. Is your microservices architecture actually driven by scaling physics, or by org chart? Conway's Law cuts both ways.
  3. How do you know when you've extracted too many services? What's your signal?
  4. If you started today with AI coding agents as a first-class team member, would you make the same architectural choices you made three years ago?
  5. Who owns the decision to consolidate? Extraction is celebrated. Consolidation is quiet. Why?