Glossary

Refactoring

Code can become more readable and easier to test without giving a user a new feature or changed business rule.

Short definition

Change the arrangement, not the promised behaviour.

Refactoring changes the structure of source code: it can remove duplication, name an unclear part, split a long method, or move a responsibility into a more suitable class. Inputs, outputs, and important side effects should remain the same.

This boundary matters. If the application is meant to behave differently, it is a feature or bug fix. If a substantial part of the system is replaced by another implementation, it is closer to a rewrite. Refactoring can prepare such work, but it is not a reason to hide all these changes in one step.

When it helps

When the current structure makes the next change unnecessarily hard

A good opportunity is not a vague feeling that code is ugly. It is a specific problem in understanding, testing, or changing it.

  • the same rule is copied in several places and may start to differ
  • one method or class has several unrelated responsibilities
  • a name hides the meaning of a value, decision, or boundary between layers
  • a new change is risky because dependencies cannot be easily traced with static analysis and tests
  • before a planned rule extension, if the starting point can first be simplified safely

Practical example

An order price calculation is written twice

Checkout and administration contain almost the same discount and rounding calculation. Before moving it, tests describe today’s results for normal and edge-case orders. This protects the rule: the price must stay the same for the same inputs after the change.

In the first small step, extract only the shared calculation into one class and have both original entry points call it. Then run PHPUnit tests and PHPStan, and let the change pass code review. If the work also changed the rule for a new type of discount, it would no longer be pure refactoring; that feature change needs its own requirement and verification.

Process

Safe refactoring in small steps

Small changes are easier to check, revert, and review. Every step should have one understandable purpose.

  1. Name the problem Describe a concrete pain: duplication, unclear responsibility, a hard-to-test branch, or an opaque dependency.
  2. Capture current behaviour Run existing tests or add a characterisation test for an important scenario. The test does not describe the desired internal design; it records what must remain true externally.
  3. Make the smallest change For example, rename an expression, extract a function, or remove one duplication. Do not mix a new rule or project-wide formatting into the same step.
  4. Verify the contracts Run relevant tests and static analysis. Check public interfaces, error states, and important side effects, not only that the application starts.
  5. Review and continue Let the change pass review, store it as a readable independent commit, and only then continue with the next step or feature.

What is what

Refactoring is not every code change

Naming the purpose of a change helps choose the right tests, pull request size, and deployment approach.

Pure refactoring

It intentionally does not change observable business behaviour. It changes structure, names, responsibility boundaries, or duplication while preserving the existing contract.

Feature and bug fix

A feature adds new expected behaviour. A bug fix intentionally changes behaviour that is wrong against a requirement or contract. Both can follow a refactoring, but separating them is clearer.

Rewrite

A rewrite replaces a substantial part of an implementation or system. It brings a larger risk of hidden differences, data migration, and operational impact; a few renames do not make it refactoring.

Optimisation

A performance change is based on measurement and can change timing, memory use, or operational properties. It can contain refactoring steps while preserving the functional contract, but success must also be measured in performance.

Benefits and risks

Lower future cost in exchange for discipline now

Benefits

  • clearer boundaries and names for future development
  • less duplication and less risk of inconsistent fixes to one rule
  • easier focused testing and dependency tracing
  • smaller, more understandable changes for code review

What to watch

  • mixing a structural change with a feature or bug fix
  • a large mechanical diff that hides the real change
  • moving code without a test for important behaviour
  • creating abstractions too early for a need that does not exist yet

Practical use

The best time is just before a safer next change.

Refactoring is often worthwhile when a team repeatedly works in the same part of a system. Once it understands the current behaviour and has basic verification, a few small steps reduce the risk of the upcoming feature and future fixes.

For sensitive parts such as payments or imports, proceed even more carefully: split changes, compare results, and use Git for traceable history and an easy return. If nobody yet knows the current behaviour, first discover it and write a characterisation test instead of immediately rewriting it.

Checklist

How to know refactoring stayed safe

Every item protects a different kind of contract. A green build alone may not catch a changed business rule.

  • a defined structural problem and declared unchanged result
  • a relevant existing or newly added characterisation test
  • completed tests, static analysis and, where useful, architecture checks
  • small independent commits without bulk formatting or unrelated changes
  • review focused on preserving the contract, not only the code’s new appearance

Common questions

When to call a change refactoring

Is a bug fix refactoring?

Not by itself. A bug fix intentionally changes behaviour from wrong to correct. Refactoring can prepare the fix by clarifying code, but the functional change should be visible in review.

Do I need tests before refactoring?

For important behaviour, yes, at least enough to protect the step. If tests are missing, start with a characterisation test or another verification of the current contract.

Is renaming a variable refactoring?

Yes, when it preserves behaviour and improves clarity. Even a small change needs care around a public API, serialized data, or configuration where the name can be part of the contract.

Should optimisation be part of refactoring?

Only when it is clearly separated and measured. Optimisation also has a performance goal and can introduce operational risks; do not hide it in a pull request labelled only as refactoring.

How I maintain code in practice

I improve structure in steps that can be verified safely.

I combine small changes, tests, and static checks so the next feature does not add unnecessary risk to an existing system.

Request a call

I will call you on the next working day between 9:00 and 17:00.

You can also call me directly.

+420 605 181 728

Leave your phone number and send a callback request.

By sending, you agree to processing your data in order to handle your request.