Friday, 21 August 2026

Modernize PHP Without Rewriting Everything — Evolve Bridge

 


There is a kind of advice developers give very easily when they are not responsible for the consequences.

“Just rewrite it.”

I have heard versions of that advice many times.

An application is old.

The framework is outdated.

The codebase has grown messy.

Dependencies are difficult to upgrade.

Nobody fully understands some parts of the system anymore.

So the clean technical answer seems obvious:

Start again.

Sometimes that is the right answer.

But in real businesses, it is often the most dangerous one.

That problem is one of the reasons I am building Evolve Bridge.

Old software is not automatically bad software

A business application can be badly structured and still be extremely valuable.

It may have been running for ten years.

It may process customer registrations every day.

It may generate invoices.

It may connect to payment providers.

It may manage stock, claims, applications, subscriptions or government records.

It may contain thousands of small business rules that were added gradually because real users discovered real edge cases.

Those rules may not be documented anywhere else.

They exist in the code.

So when somebody says:

“We can rebuild this in six months.”

what they often mean is:

“We can rebuild the parts of the system we currently understand in six months.”

Those are not the same thing.

Rewrites hide risk

Suppose a business has this application:

Legacy PHP Application
├── Authentication
├── Customers
├── Billing
├── Orders
├── Reporting
├── Notifications
├── Admin
└── Third-party integrations

Maybe it was written using an older version of Laravel.

Maybe CodeIgniter.

Maybe Symfony.

Maybe CakePHP or Yii.

Maybe there is no framework at all.

After years of development, the team decides the architecture is becoming difficult to maintain.

A rewrite begins.

Now the company has two systems:

Existing Application
        +
New Application

The old one is still serving customers.

The new one is trying to catch up.

But the business does not stop changing while the rewrite happens.

A new tax rule arrives.

A payment provider changes its API.

Management wants a new approval workflow.

A customer discovers an important bug.

I have experience this in my former employment while they were adding new features to their existing Laravel application and rewrite the existing application on Node.js.

A regulator asks for another report.

Where do those changes go?

Usually both systems begin changing at the same time.

That is when the rewrite becomes more difficult.

The finish line keeps moving.

I think modernization should be smaller than that

This is the problem Evolve Bridge is intended to address.

Instead of beginning with:

“How do we replace this application?”

start with:

“What capability actually needs to change?”

That creates a very different modernization strategy.

Imagine the legacy application's reporting system has become painful.

Maybe generating reports takes too long.

Maybe reporting code is tightly coupled to everything else.

Maybe the business wants a new analytics team to work on it independently.

Instead of rebuilding the whole application, we could create a boundary:

Existing PHP Application
├── Authentication
├── Customers
├── Billing
├── Orders
├── Notifications
└── Admin

           |
           |
      Evolve Bridge
           |
           v

     Reporting Module

The old application continues working.

Only Reporting moves.

If the migration succeeds, perhaps another capability moves later.

If it does not make sense to move anything else, we stop.

That is perfectly acceptable.

Modernization should not become a religion.

Evolve Bridge is not a code converter

This distinction is important.

The goal is not:

Laravel code
    ↓
magic converter
    ↓
EvolvePHP code

I don't think serious modernization works that way.

Frameworks have different lifecycle assumptions.

Applications make different architectural decisions.

Business logic becomes mixed with framework behavior.

Automated conversion may help with mechanical work, but it cannot safely understand every architectural decision in a mature application.

So Evolve Bridge is being designed as an integration boundary, not a rewrite engine.

The job of the Bridge is to help two systems coexist deliberately.

For example:

Laravel
   |
   | delegated operation
   v
Evolve Bridge
   |
   v
Evolve Module

or:

Legacy PHP
     |
     | HTTP
     v
Evolve Service

or eventually:

Symfony Application
       |
       | Queue/Event
       v
  Evolve Capability

The integration mechanism can differ.

The principle stays the same.

One capability at a time.

Sometimes the systems can live in the same process

For compatible modern PHP applications, one possible Bridge model is embedded integration.

Conceptually:

Laravel / Symfony
       |
       v
  Evolve Bridge
       |
       v
  Evolve Module

Both systems run inside the same PHP process.

The host framework still owns the main application.

It may continue owning:

  • routing,

  • sessions,

  • existing authentication,

  • the top-level error lifecycle,

  • existing controllers,

  • existing business capabilities.

EvolvePHP only owns the part delegated to it.

That matters because I do not want integrating EvolvePHP to mean secretly placing another framework in control of the entire application.

Ownership has to be clear.

Other applications need process separation

Same-process integration is not always safe or possible.

Imagine an application running:

PHP 7.x
old framework
old Composer dependencies

while EvolvePHP 2 requires a modern PHP runtime and modern dependencies.

Trying to force those dependency trees into the same process would be a bad idea.

In that case the better architecture may be:

Legacy Application
       |
       | HTTP / Queue / Events
       v
 EvolvePHP Service

Now each side can have its own:

  • PHP version,

  • dependencies,

  • release cycle,

  • process lifecycle,

  • deployment strategy.

That is a stronger isolation boundary.

It also introduces distributed-system concerns such as latency, timeouts and retries.

Those concerns should not be hidden.

Remote integration is more expensive than an in-process call.

But sometimes that cost is exactly what allows an old system to keep running while new capabilities move forward.

One capability needs one owner

There is another rule I consider important.

During migration, it is easy to create situations where both systems think they own the same thing.

That becomes dangerous.

For example:

Legacy Billing
      +
New Billing

Which one is responsible for the invoice?

Which one owns the database record?

Which one applies refunds?

What happens if one succeeds and the other fails?

Modernization can accidentally create more complexity than it removes if ownership is unclear.

So the Bridge direction assumes something much simpler:

At any point in the migration, a capability or business aggregate should have one authoritative owner.

That owner can change during migration.

But the transition should be explicit.

Database ownership is one of the hardest parts

Moving controllers is easy.

Moving ownership of data is much harder.

Imagine an Orders module that currently writes to twenty legacy tables.

There are several modernization approaches.

You might initially allow the new module to read existing data through a carefully defined adapter.

Later you might introduce a new model.

Eventually the source of truth might move.

The important thing is that this transition should be planned rather than accidental.

Conceptually:

Stage 1
Legacy system owns data
Evolve reads through adapter

then perhaps:

Stage 2
Legacy owns old records
New operations delegated to Evolve

and eventually:

Stage 3
Evolve owns capability and data
Legacy becomes consumer

There is no single migration strategy that fits every application.

Evolve Bridge should provide boundaries and tooling.

It should not pretend difficult data migration questions disappear.

Authentication has the same problem

A legacy application may already know who the user is.

EvolvePHP should not necessarily require the user to authenticate twice simply because one capability has moved.

Instead, the host may translate the identity into a trusted integration contract.

But there is an important difference between:

"This host says the user is Josiah"

and:

"Josiah is allowed to perform this operation"

The first is identity.

The second is authorization.

EvolvePHP should still authorize operations it owns.

That means Bridge integration needs explicit trust boundaries.

Authentication data should not simply be copied between frameworks and assumed to be safe.

Remote writes are particularly dangerous

One area where I do not want Evolve Bridge to hide complexity is state-changing remote operations.

Imagine:

Legacy Application
      |
      | POST /payment
      v
Evolve Service

The request times out.

Did the payment happen?

A timeout does not mean:

“Nothing happened.”

The remote side may have completed the operation and the response was simply lost.

If the legacy application retries blindly, it could perform the operation twice.

This is why remote modernization eventually needs patterns such as:

  • idempotency keys,

  • operation identifiers,

  • reconciliation,

  • explicit failure states,

  • safe retry policies.

This kind of behavior is especially important in financial and enterprise systems.

Framework integration should not give developers false confidence around distributed failure.

Rollback matters as much as migration

Developers naturally think about the happy direction:

Legacy
   ↓
Modern

But real migrations sometimes fail.

A new capability may have performance problems.

The integration may behave differently under production traffic.

An important edge case may be missing.

The company may need to temporarily return traffic to the old implementation.

So the modernization process should also ask:

How do we go back safely?

That could involve:

route ownership
feature flags
deployment version
data compatibility
migration checkpoint
rollback validation

A migration without a rollback story is not a controlled migration.

It is a bet.

Bridge should be useful before the migration begins

The more I have thought about modernization, the more I have realized that the actual integration layer is only one part of the problem.

Before moving anything, teams need to understand what they have.

That is why the broader EvolvePHP modernization direction now includes tools such as:

Evolve Audit
     ↓
Evolve Doctor
     ↓
Adoption Plan
     ↓
Evolve Bridge
     ↓
Modernize

Evolve Audit is intended to help answer questions like:

  • What PHP version is this system using?

  • Which dependencies are abandoned?

  • Where is global or static state being used?

  • Where are the strongest coupling points?

  • Which areas look like natural capability boundaries?

  • What could prevent persistent-runtime adoption?

  • Which parts of the application are the best modernization candidates?

Doctor has a more operational role.

It should answer things like:

  • Is the environment correctly configured?

  • Are required extensions available?

  • Is this application safe for the runtime being proposed?

  • Are there configuration or lifecycle problems that would make the migration unsafe?

I think modernization starts with diagnosis.

Not with writing new code.

This also changes how EvolvePHP competes

EvolvePHP does not need to convince every framework developer to stop using their preferred framework.

If EvolvePHP only provides value after you move the whole system to EvolvePHP, adoption becomes extremely expensive.

I want the opposite.

The framework should be able to earn trust gradually.

This is important for enterprise systems

Enterprise applications rarely have the luxury of being replaced overnight.

A government platform may have hundreds of workflows.

A bank may have dozens of surrounding systems connected to its core platform.

An ERP may contain years of company-specific behavior.

A marketplace may have sellers, buyers, billing, messaging, search and logistics integrations.

The safest modernization strategy is often not:

old system → new system

It is closer to:

old system
    |
    +---- capability A
    |
    +---- capability B
    |
    +---- capability C

and then gradually:

old system
    |
    +---- capability A
    |
    +---- Evolve capability B
    |
    +---- capability C

and later perhaps:

old system
    |
    +---- Evolve capability A
    |
    +---- Evolve capability B
    |
    +---- capability C

There may never be a dramatic rewrite day.

The architecture simply evolves.

I think that is healthier.

Sometimes the correct decision is not to migrate

This is also something modernization tooling should be able to tell you.

Suppose Audit examines an old capability and you discover:

  • it works reliably,

  • it rarely changes,

  • it has no serious security problems,

  • there are good tests,

  • maintenance cost is low.

Why rewrite it?

Modernization should solve business and engineering problems.

Not satisfy architectural fashion.

A good modernization platform should sometimes say:

Leave this alone.

That is a feature, not a failure.

Evolve Bridge is really about reducing the cost of change

The idea behind EvolvePHP 2 has increasingly become less about:

“How do I build another PHP application?”

and more about:

“How do I make PHP applications easier to change over their lifetime?”

For greenfield systems, that means starting modular.

For existing systems, it means creating controlled paths to evolve.

Evolve Bridge sits between those two worlds.

It should allow something built ten years ago to cooperate with something being built today.

Not because the old architecture is perfect.

Not because the new architecture is automatically better.

But because replacing a working business system all at once is often unnecessary risk.

What success would look like

If Evolve Bridge works the way I want, a modernization conversation might eventually look like this:

We have a twelve-year-old PHP application.

Fine.

It cannot be rewritten right now.

Fine.

We want to move Billing first.

Let's analyze the boundary.

Authentication must remain in the old application.

Fine.

The old application is running an incompatible PHP version.

Use a remote boundary.

We need rollback.

Define ownership and rollback before cutover.

After Billing works, we may move Reporting.

Good.

We may never move Customer Management.

Also good.

That is very different from telling the company:

“Come back when you're ready to rebuild everything.”

Modernize without rewriting everything

I don't think the future of PHP depends only on helping developers create more new applications.

There are already enormous amounts of PHP software running businesses today.

A lot of it will still be running five or ten years from now.

The interesting question is what happens to those systems as technology changes around them.

New PHP versions.

New deployment environments.

Persistent workers.

Cloud infrastructure.

New security requirements.

New observability expectations.

New business requirements.

Those applications need somewhere to go.

Evolve Bridge is my attempt to create one possible path.

Not:

Rewrite everything.

But:

Understand what you have. Create a boundary. Move what needs to move. Keep what still works. Repeat only when it makes sense.

That is the modernization philosophy behind EvolvePHP.

Modernize PHP without rewriting everything.

No comments:

Post a Comment