I / Field notes

How to modernize a React product without betting on a rewrite

A risk-weighted modernization framework for choosing seams, proving a target pattern, and improving a React product while useful delivery continues.

  • Incremental modernization
  • Delivery risk
  • React architecture

A rewrite offers a clean story: the current product contains years of constraints, the new product will use consistent patterns, and feature development can resume once the replacement is ready. The risk is that the business must fund two systems while the new one rediscovers requirements already encoded in the old one.

Incremental modernization is less dramatic. It replaces a sequence of bounded risks while useful delivery continues. That requires a clear target direction, but it does not require pretending that the whole product can move at once.

I-01

Build a risk map before a replacement plan

Inventory the areas that create real delivery friction, then score each one against four factors:

  • Change pressure: how often will product work touch this area in the next planning horizon?
  • Failure cost: what customer, operational, security, or revenue impact follows a mistake?
  • Dependency reach: how many routes, features, packages, or teams depend on it?
  • Learning value: will changing this area prove a pattern the team can reuse elsewhere?

High change pressure and high failure cost usually deserve early attention. High dependency reach increases the need for a controlled seam. Learning value helps select a first slice that informs later work instead of creating an isolated modern island.

I-02

Decide whether to retain, contain, or replace

Modernization does not require treating all old code equally.

Retain what is stable and understood

Code can be old and still be a reliable asset. Retain it when behavior is understood, change is infrequent, failures are contained, and its dependencies are supported. Changing it may produce no meaningful product or ownership benefit.

Contain what is necessary but risky to disturb

Wrap unstable providers, legacy state, or difficult APIs behind an explicit adapter. Containment gives new work a cleaner contract while buying time to understand the old behavior. It is valuable only when the boundary is owned and the temporary compatibility layer is visible.

Replace what blocks repeated valuable change

Replace an area when it is frequently changed, hard to verify, and responsible for recurring delivery or production risk. The replacement should start at a seam where old and new behavior can coexist long enough to compare and recover safely.

I-03

Modernize one vertical slice at a time

A controlled slice follows a repeatable sequence:

  • Describe the current behavior, including loading, empty, failure, authorization, and recovery paths.
  • Add the minimum protection needed to detect unintended behavior changes.
  • Define the target boundary and the contract between old and new code.
  • Implement one end-to-end product path through the target pattern.
  • Release it with observable success and failure signals.
  • Record what the slice proved, then adjust the next slice before repeating.

The slice should be commercially meaningful enough to test the architecture but small enough to roll back. A folder-by-folder migration rarely provides that feedback because it reorganizes technical layers without completing a user or operational outcome.

I-04

Control the number of parallel conventions

Incremental work temporarily creates two ways of doing something. That is acceptable when the transition is explicit; it becomes expensive when both approaches spread.

For each target pattern, define where it is mandatory, where the legacy approach is temporarily allowed, and what removes the exception. Reviews should prevent new legacy usage inside the selected boundary while leaving unrelated areas stable.

A useful modernization board tracks seams rather than broad technical ambitions: current risk, target contract, first slice, evidence from release, remaining users of the old path, and the developer who can own the next step.

I-05

Measure progress by reduced uncertainty

Lines rewritten and packages upgraded describe activity, not modernization value. Better signals ask whether the product and team can change with less risk:

  • Fewer high-change features depend directly on the legacy boundary.
  • The target pattern has survived a real production path and failure scenario.
  • The team can implement the next slice without depending on its original author.
  • Duplicate conventions are decreasing rather than multiplying.
  • Supported dependencies and operational signals cover the area being changed.
  • Product delivery continues without a growing merge or release bottleneck.

These signals make the stopping point visible. A modernization programme can end when the remaining legacy areas are stable, contained, and cheaper to keep than to replace. Completeness is not the goal; durable change capacity is.

I-06

Where this fits

Modernize Without Rewriting turns this framework into a sequenced engagement: identify the costly boundaries, establish a proven target pattern, migrate valuable slices, and transfer the approach to the team continuing the product.

Explore Modernize Without Rewriting