Modernising without starting again

Sometimes the difficult engineering decision is to keep what already works.

2 min read

When you spend time in mature software systems, you learn that rewriting everything is rarely the only option, and often isn’t the best one.

Upgrading older PHP and MySQL applications isn’t just changing version numbers. Existing code may depend on behaviours that newer runtimes and databases no longer tolerate.

The hidden contracts

A warning that used to go unnoticed can become a production issue. A query that happened to return the desired result can fail under stricter grouping rules. Previously accepted dates can become invalid. Those assumptions need to be understood before architecture changes are made.

Controlled change beats a heroic rewrite

My preference is to establish a reliable test baseline, improve observability and make changes incrementally. Some problems need targeted compatibility fixes. Others deserve redesign. Those shouldn’t be confused.

In practice, on a recent PHP 7.4 to 8.2 and MySQL 5 to 8 upgrade, that meant writing regression tests around the behaviour people relied on before touching the runtime, then fixing compatibility issues one application at a time. The tests made each release boring, which is exactly what you want from a migration.

On another platform, incremental replacement using the Strangler Pattern allowed parts of an older system to evolve without shutting down the business workflows that depended on it.

Keep the business in the conversation

A cleaner architecture is valuable when it improves reliability, maintainability or delivery. A rewrite that delays useful work needs a stronger reason than ‘this would be nicer to build’.

The aim isn’t to make every system new. It’s to make the systems people depend on safer to change.