Take over or modernise an older codebase: tests first, then refactors, then features

An old codebase that still earns its keep deserves better than a rewrite. The safe order is tests first, so you know what the code does today; then small refactors you can read and revert; then the features that have been waiting. ProPR makes each step a pull request, which keeps the order honest.

Overview

Example project. Courtside is a ten-year-old booking system for a sports club: PHP, a MySQL database, no automated tests, and a pricing calculation nobody dares touch. The developer who wrote it has left. The project is an illustration written to show the steps.

Old code worked on this way: a ten-year-old mobile app takes new languages, platform bugs and crash fixes as reviewed pull requests, more than 110 merged.

Keep the stack, add a safety net

Nothing gets replaced in month one. The first issues give the project what it lacks: a way to install and run it in a clean workspace, and tests that record what the code does today. Everything after that is checked against those tests.

Add the repository and let ProPR read it

In ProPR, open Repositories, choose Add Repository, and enter the repository name. ProPR indexes the code so the planner knows the file structure and the dependencies before you ask for anything. Then run the improvement scan: it reads the repository and lists what it finds, from missing tests to risky functions. Keep the suggestions that matter and discard the rest.

Plan the first month: tests first

Open Planner Studio, pick the repository, and say what you want in plain words.

This is an old PHP booking system with no tests. Do not change behaviour. First make the project install and run its checks in a clean workspace. Then write tests that pin down what the pricing calculation, booking creation and cancellation do today, using real examples from the database fixtures. Only after that, refactor the pricing code into one well-named module with the tests still green. Keep every task small enough to review in ten minutes.

Refine the plan in chat until each task is one safe step. Approve, and ProPR files one GitHub issue per task.

Reviewing a plan: the payment-and-review step with its requirements and acceptance criteria, beside the assistant chat that reshaped it
Acceptance criteria and the refinement assistant, side by side, before implementation.

The plan becomes issues

The issues come with checklists of what done means. A first plan for this system looks like this.

  1. Make the project run in a clean workspaceDone when: a setup script installs the PHP version and dependencies the project needs, a test database loads from fixtures, and one smoke test proves the home page renders.
  2. Tests that pin the pricing calculationDone when: tests cover peak and off-peak rates, member discounts and the end-of-month rollover with the exact totals the code produces today, and every test passes without a single change to the pricing code.
  3. Tests that pin booking creation and cancellationDone when: tests cover double-booking refusal, the 24-hour cancellation rule and the refund amount, again against today's behaviour.
  4. Extract pricing into one moduleDone when: all pricing logic lives in one class with named methods, call sites use it, and every pinned test passes unchanged.
  5. Upgrade the framework by one versionDone when: the dependency moves up one major version, deprecations in the changed code are fixed, and the full suite passes.
  6. First new feature: online cancellationDone when: a member cancels a booking from their account page under the existing rules, the refund uses the pricing module, and new tests cover the screen and the rule.

Run it in order, with a quality bar

Choose Execute as Epic PR so the issues run one after another on one branch; a refactor must build on merged tests. Turn on Run ultrafix after PR with a minimum review score. Each pull request then gets a review, fixes for the findings, and a second review before it reaches you, which is the right level of care for code that nobody fully understands yet. The Ultrafix playbook shows one pull request's loop minute by minute.

Execution settings for every task in the plan: agent and model, Ultrafix with a minimum review score of 8/10 and a loop limit, and auto-merge
A default agent and model, auto-merge, and Ultrafix to a minimum score.

What you look at in each pull request

  • In the test pull requests: the examples. Do the totals in the tests match what the club charges? If one looks wrong, that is a bug you have found, and it gets its own issue later. The tests pin today's behaviour first.
  • In the refactor pull requests: two things only. The pinned tests passed unchanged, and the diff moves code without adding behaviour. Ask a second model to review any refactor that touches money.
  • In the feature pull requests: the screenshot and the new tests, like any other project.
@youcommented on the pull request

The member discount test uses 10%, but the club charges 15% for members since 2023; check the rates table fixture. Pin whatever the code does today and add a note in the test naming the expected value, so we fix it in a separate PR.

A new commit lands on the same pull request. If a merged refactor turns out to change behaviour after all, you revert that pull request and the pinned tests tell you the system is back where it was.

How the modernisation continues

Repeat the pattern module by module: pin, extract, upgrade, then feature. Hand the wide, open-ended outcomes to a goal, such as bringing test coverage of the booking flow to a level you set, and steer it from its draft pull request. Schedule an automation that reports every Monday which parts of the code still have no tests and which dependencies have fallen behind. The waiting feature list shrinks as the safety net grows.

Good to know

  • The agent's workspace comes with Node.js and Python. A project in another language gets its toolchain through the repository's setup script, which runs without administrator rights, or through a custom agent image; the agent runtime docs cover both.
  • The agent never reaches your production database. Tests run against fixtures in the repository, so the first issue gives the project a realistic fixture set.
  • Your branch protection and required checks apply to every pull request ProPR opens. Auto-merge is a per-plan choice you turn on when the tests have earned your trust.

Start on the codebase you inherited.

Everything above happens in a browser. ProPR Hosted gives you your own instance, run by the ProPR team; the live demo lets you click through plans and pull requests first.

On your own server, self-host ProPR, free and open source.

All Build something walkthroughs