FAQ · Software Engineering

Software Engineering — Frequently Asked Questions

Answers on the practices that decide whether a codebase stays workable — code review, technical debt, estimation, documentation, legacy code, and how much process a small team actually needs.

Code review#

What is code review actually for?#

Catching defects a reviewer can realistically catch, and spreading knowledge so more than one person understands each part of the system. The second benefit is usually the larger one and is almost never measured.

It is not for enforcing personal style — that belongs to a formatter, applied automatically, so nobody spends attention on it.

How large should a pull request be?#

Small enough to review properly in under an hour. Beyond that, review quality collapses: large diffs receive approvals, not scrutiny, and everyone involved knows it.

If a change is genuinely large, split it into a sequence — refactor first with no behaviour change, then the behaviour change on top. The second PR then shows exactly what is new.

How do we stop reviews becoming an argument?#

Label each comment as a defect, a question, or a preference. Most friction comes from taste being delivered with the same weight as a bug, leaving the author unsure what actually blocks the merge.

Then set a norm on turnaround. A review waiting three days does more damage to a team's output than a merge that was slightly imperfect.

Technical debt#

How do we explain technical debt to the business?#

Translate it into time and risk, not virtue. "This change takes three days instead of half a day because of X" and "we cannot deploy this on a Friday because of Y" are arguments a business can act on. "The code is messy" is not.

Keep a short list of the specific debts that are actually costing you, with the cost attached. Vague debt is never funded, and reasonably so.

Should we fix debt continuously or in dedicated time?#

Mostly continuously, in the area you are already working — that is where the context is and where the payoff is immediate. Reserve dedicated time only for things too large to do incrementally, with a defined outcome and an end date.

Standing "refactoring sprints" without a specific target tend to produce change without benefit, and they are the first thing cut when a deadline appears.

When is a rewrite the right answer?#

Rarely. Justified when the platform is genuinely unsupported, or when a requirement cannot be met by any incremental path. Not justified because the code is unpleasant.

The usual better route is to strangle it: put the new implementation in front, move one capability at a time, keep shipping throughout. A rewrite trades a working system with known problems for a non-existent system with unknown ones, and it always takes longer than the estimate that justified it.

How do we work with legacy code we do not understand?#

Get a test around the behaviour before changing it, even a crude one that captures current output. Then change in small steps, verifying as you go.

Resist the urge to tidy while you are in there. Mixing a behaviour change with a cleanup means that when something breaks, you cannot tell which caused it — and in unfamiliar code, something usually breaks.

Estimation and planning#

Why are our estimates always wrong?#

Because they are estimates of the work you can see, and the cost lives in what you cannot: the integration that behaves differently in practice, the edge case discovered halfway, the environment that does not match, the review cycle.

Two things help more than better estimating technique. Break work down until pieces are small enough to be understood concretely — small items are wrong by less. And track actual versus estimated for a few months so your own bias becomes visible; most teams find a consistent multiplier.

Should we estimate in points or in time?#

Whichever your team reasons about more honestly. Points were meant to avoid false precision and frequently become a currency to be maximised; hours are concrete and invite a commitment nobody intended.

The mechanism matters less than whether the number is used to plan or to judge. As soon as it is used to judge people, all estimates become negotiation and the information is lost.

Documentation and testing#

How much documentation should a codebase have?#

Enough that a new engineer can run it, deploy it and find their way to the important parts. Then decisions — why the architecture is what it is, what was tried and rejected.

Documentation that describes current behaviour in detail goes stale fastest and misleads most, because a confidently wrong document is worse than none. Prefer things that stay true: decision records, a good README, tests that show intended use.

What should comments say?#

Why, not what. The code already says what it does; if it does not, that is a naming problem a comment cannot fix.

The comments worth writing explain a non-obvious constraint, a workaround for a real bug elsewhere, or a decision that looks wrong until you know the reason. Those save someone hours.

How much test coverage do we need?#

Coverage is a diagnostic, not a target. High coverage with weak assertions proves that code ran, not that it works, and chasing a percentage produces exactly those tests.

Ask instead: if this breaks, which test fails? Concentrate effort on the logic that would be expensive to get wrong, on error paths, and on the boundaries where systems meet — that is where defects concentrate and where tests earn their maintenance cost.

Working as a team#

How much process does a small team need?#

Enough that work is visible and nothing important depends on one person remembering it. For most small teams that is: version control with reviewed changes, CI that runs tests, a shared list of what is in progress, and a short regular conversation about what is blocked.

Process should be added in response to a specific failure that actually occurred, and removed when the failure stops occurring. Process inherited from a larger organisation is the most common source of ceremony nobody values.

How should we handle disagreement about approach?#

Timebox the discussion, then decide — and record the decision with its reasoning. Most technical disagreements are between two acceptable options where the cost of deciding slowly exceeds the difference between them.

For genuinely consequential and hard-to-reverse choices, spend the time and write it up properly. Knowing which kind you are in is most of the skill.

What single practice has the largest effect on quality?#

Small changes, reviewed and integrated frequently. Nearly every other good practice becomes easier when changes are small: review is real, tests stay fast, rollback is safe, and defects are easy to attribute. Nearly every practice becomes theatre when changes are large.

Back to Software Engineering