DEV Community

Cover image for How to reduce technical debt in every pull request
Edvaldo Freitas for Kodus

Posted on • Originally published at kodus.io

How to reduce technical debt in every pull request

A technical debt does not appear out of nowhere after a bad sprint. It works more like a tax you pay on every future feature. And it almost always comes from the small decisions we make every day. A shortcut that seemed harmless, a bad variable name, a test that got pushed to later “just this once.” The most efficient way to reduce technical debt is not a massive refactoring project. It is changing how you handle each pull request.

Many teams treat the PR as the last step before the merge. CI passed? Move on. But that misses the main point. The PR is the best tool you have to stop debt from getting into the code. It is where the team crosses context, standards, and decisions.

The problem is that everyone is rushing. And then small things slip. The famous phrase “we will fix it later.” You know how that ends. That “later” becomes a forgotten ticket and, months down the line, becomes the cause of a production failure.

The role of a tech lead is not to become a bottleneck reviewing line by line. It is to create a system where quality is the default. And that system starts by adjusting how your team handles PRs.

The PR, your best and most ignored tool against technical debt

Why is the PR process so important?

Because it is the last time someone looks at the change before it lands in main. It is the moment when intention “I am going to fix this bug” meets implementation “here is the code.” It is where you make sure the solution does not create three new problems while solving one.

Treating technical debt reactively “refactoring sprint”, “cleanup week” is a clear sign that the process is not working. Sometimes it is unavoidable, but it is expensive and only fixes the symptom. When you put the PR at the center, you control what gets in. You are not only paying old debts. You are preventing new ones from being created.

Defining the standard

The role of a tech lead is not to review everything alone. It is to define the standard the whole team will follow. You act more like an editor than an executor. You guide the direction, define what quality means, and make sure anyone can apply those criteria when reviewing a PR.

For that to work, “good” cannot be an opinion. It needs to be something concrete. Subjective feedback does not help.

“I did not like this” does not say what needs to change. “This function went over the complexity limit we agreed on, let’s break it down” does.

When the team operates with clear criteria like this, the review stops depending on someone’s mood or personal preferences and becomes a predictable, repeatable, and shared process.

Some approaches to reduce technical debt in PRs

Let’s go to the practical part. How do you turn this vision into something that works day to day?

Create simple and clear review guidelines

Add a short guide in your CONTRIBUTING.md explaining how to review a PR. Nothing long. Just the essentials to help anyone on the team know what to look for.

  • Correctness: Does this code do what it is supposed to do? Does it solve the problem described in the ticket? Does it introduce any bug or edge case?
  • Maintainability and readability: Will a new developer understand this code six months from now? Are variable names clear? Is the logic straightforward or a bowl of spaghetti? Is it consistent with the existing standards of the codebase?
  • Performance and security: Is this introducing an N plus 1? Is it handling user input safely? Are we adding a dependency with known vulnerabilities?
  • Tests: Do the tests actually validate the new logic? Are they testing implementation details fragile or behavior robust? Is there adequate coverage for critical paths?

This is not a mandatory checklist for every PR, but a guide for whoever is reviewing. It is only a way to avoid vague reviews and give the team a shared north.

Focus on incremental refactoring

The “scout rule” is your best friend. Always leave the code better than you found it.

If a developer is working in a messy area to fix a bug, give them autonomy to clean up the immediate surroundings. There is no need to refactor the whole module. Just rename a few confusing variables. Extract a complex condition into a well named function. Add a missing test.

This needs to be encouraged explicitly. If the team is measured only by story points, no one will stop to make these small improvements. It is important to make clear that these adjustments are part of the work and have real long term impact. When someone does it, acknowledge it in the team chat. Showing that this matters changes team behavior.

How to do a good review without blocking the sprint

A good review process finds balance between quality and speed. The goal is to improve the code, not win an argument or prove you are smarter.

Create a minimum viable checklist in the PR template

Do not turn this into bureaucracy. Just a few simple boxes in the PR description template can help a lot.

Example of a PR template:



Differentiate blockers from suggestions

This is essential. Not every comment carries the same weight and the PR author needs to know that without guessing. Use simple prefixes to make the intention clear.

[Blocker] Something that must be fixed before merging.

Example: [Blocker]: This new query does not have an index and can lock the table.

[Suggestion] Something that can improve the code but does not block the merge.

Example: [Suggestion]: You could use map here instead of forEach. It is up to you.

[Question] When you truly did not understand the reason for the change.

Example: [Question]: Why did this line need to be changed? I am missing context.

This simple convention reduces friction and helps the PR author prioritize what needs immediate correction and what can be revisited later.

Common anti patterns that create debt in reviews

Some behaviors show up in almost every team and if you do not handle them, they quickly become debt.

The automatic “LGTM”: Approving only because CI passed. It is basically saying that quality is optional.

The mega PR: A PR with thousands of lines will not be reviewed properly. People skim through it, make one or two comments, and move on. Encourage smaller PRs with clear scope.

Endless style debates: Arguing over a variable name that does not break any defined standard is a waste of time. That is work for linters and formatters, not humans.

The famous “fix it later”: It is the phrase that creates the most technical debt. If something is wrong, fix it now. If it is a bigger change, record the problem, but do not let the PR worsen the current state of the codebase.

In the end, it all comes down to culture

Tools help. Process helps. But only up to a point. Reducing technical debt is ultimately a cultural task. It is about creating an environment where people can say when a deadline is sacrificing quality, where small refactors are part of everyday life, and where feedback is seen as code evolution, not as a personal attack.

Start small and then adjust and evolve.

Top comments (0)