MV Michael van Leest AI, cloud, and platform engineering
Home Blog About Contact

Blog post

How to improve a monolith incrementally without forcing a rewrite

A practical guide to improving a monolith incrementally, including boundary cleanup, ownership, deployment friction, and how to make real progress without forcing a rewrite.

Many monoliths do not need a rewrite. They need honesty, better boundaries, and less accumulated friction.

That distinction matters because teams often jump from “this system is awkward” to “this system is fundamentally wrong.” In many cases, that is not true.

The system may be hard to change, but the answer is often incremental cleanup, not a forced escape plan.

Start with the friction, not the future architecture

If I am improving a monolith, I do not start by drawing the target microservices model.

I start by asking:

  • where do changes slow down?
  • where is ownership unclear?
  • which parts of the codebase create repeated fear during deployment?
  • where do operational problems keep returning?
  • which internal boundaries are already trying to exist but are still being ignored?

Those are the places where incremental work usually pays off first.

Improve one change path at a time

I like cleanup work that makes a normal change easier within weeks, not cleanup work that mainly improves the architecture story.

That might mean:

  • separating one confusing module boundary
  • clarifying one domain ownership line
  • reducing one deployment hotspot
  • introducing one better interface around a painful dependency
  • deleting one category of repeated workaround

Those changes often look smaller than people expect, but they are the ones that restore confidence.

Cleanup should reduce ambiguity

If incremental monolith work is valuable, it is usually because it reduces ambiguity somewhere important.

That might be ambiguity about:

  • who owns a part of the system
  • where a workflow really begins or ends
  • what data a module is allowed to manage
  • what can be changed safely without surprising another team

I think this is one of the most useful ways to judge cleanup work. If the work does not make the system easier to reason about, it may be refactoring without leverage.

Use internal boundaries before external ones

Small teams often do better by strengthening internal boundaries before splitting systems apart.

That gives the team a chance to test whether the boundary is actually real:

  • does ownership improve?
  • does the interface become clearer?
  • does the change path improve?
  • does the module feel more self-contained over time?

If the answer is no, pushing the same boundary into separate services usually does not fix it. It just makes the ambiguity distributed.

Make the monolith easier to operate as well as easier to read

I care less about whether cleanup looks elegant in the repository and more about whether the system gets easier to live with.

That often means improving:

  • deployment predictability
  • observability in the most confusing areas
  • ownership visibility
  • testability around fragile flows
  • configuration clarity

The point is not only to make the code nicer. It is to make the system safer to change.

My default advice on incremental monolith cleanup

If a monolith is still the main delivery vehicle, improve it where it hurts instead of assuming the answer is replacement.

Start with the boundaries that are already trying to emerge.

Reduce ambiguity.

Make the common change path safer.

And do not confuse discomfort with disqualification. Many monoliths become much more effective once teams stop trying to escape them conceptually and start improving them deliberately.

Contact

Working on AI, cloud, or platform modernization?

If you are hiring, shaping a project, or need an experienced technical sounding board, use the contact form and send a little context.