DEV Community

137Foundry
137Foundry

Posted on

How to Document and Track Technical Debt

Most technical debt doesn't get documented. It lives in the mental models of senior engineers, surfaces during code reviews, gets discussed in Slack threads, and then disappears when those conversations end. The next engineer who touches that part of the codebase encounters the same problem fresh, without the context of why it exists, how severe it is, or whether anyone planned to address it.

Documenting and tracking technical debt doesn't eliminate it, but it changes the team's relationship with it. Problems that are written down, categorized, and scored are problems that can be reasoned about systematically. Teams that maintain an inventory can have productive prioritization conversations. Teams without one are stuck arguing about gut feelings with no shared reference point.

Why Mental Models Fail at Scale

For very small teams, the "everyone knows where the problems are" approach mostly works. Five engineers can hold the system state in their heads, can remind each other of the known issues, and can make reasonable prioritization calls based on shared context.

This breaks down quickly as teams grow. At ten engineers, the mental model is fragmented. Different engineers have complete knowledge of different subsystems but incomplete knowledge of the whole. At twenty engineers, the fragmentation is severe enough that a junior engineer joining the team has almost no reliable way to understand the actual risk profile of the codebase beyond what's visible in recent bug reports.

Fragmented mental models also create planning problems. When engineering estimates consistently come in higher than expected, and when bugs cluster around certain parts of the system, the missing piece is usually a shared map of where the debt actually is. Without the map, every estimate is made without context that should be influencing it.

What a Debt Record Should Contain

A useful technical debt record has enough information to evaluate the item without requiring the reader to read the code. At minimum, each record should include:

  • Location: The specific file, module, service, or subsystem where the debt lives
  • Type: The category of debt (architectural, code quality, security, test coverage, dependency)
  • Description: What the problem is, in specific terms. "The authentication service is messy" is not useful. "The session management logic has three competing implementations that were merged during a migration and were never reconciled" is useful.
  • Impact: What happens when this debt manifests. Increased bug rate, deployment friction, inability to add specific features, security exposure.
  • Estimated remediation effort: A rough order-of-magnitude estimate. "1-2 days," "1-2 sprints," or "multi-quarter rewrite" is enough to enable prioritization without needing a full engineering spec.
  • Discovery date: When the item was added to the inventory. This lets you track whether debt is accumulating faster than it's being resolved.

Capturing Context and Origin

One of the most valuable pieces of information in a debt record is why the code was built this way. This context is most accessible at the moment of discovery, when someone who knows the history is already thinking about the item.

For deliberate debt, the context is usually recoverable: "We skipped proper validation here because we needed to ship the integration before the contract deadline. The intent was to add it in Q2." That sentence makes the record useful in a way that a bare description doesn't.

For inadvertent debt, where nobody deliberately chose the shortcut, the context note might be: "Pattern predates our adoption of async handling. Written when the team was smaller and this module was accessed by one workflow. Now accessed by seven." This tells the next engineer both what to expect and why the refactoring scope is larger than it appears.

Origin context also matters when communicating debt to non-technical stakeholders. "We made a deliberate trade-off that we're now reversing" is a very different conversation than "we've identified a problem we didn't know we had." Both are valid, but they require different framing.

Where to Store the Inventory

The specific tool matters less than the discipline of using a shared, searchable location. The primary options each have real trade-offs.

Issue trackers: GitHub Issues, Linear, or Jira work well because technical debt records live in the same tool as feature work. This makes them easier to pull into sprint planning and keeps the debt backlog visible alongside the feature backlog. The main risk is that debt issues get buried under feature issues without careful labeling and triage discipline.

Spreadsheets: Simple to set up and easy to share with non-technical stakeholders. Sorting and filtering by category, priority, or estimated cost is straightforward. The downside is that spreadsheets require manual updating and don't integrate with the development workflow in any meaningful way.

Automated analysis tools: SonarQube, CodeClimate, and Codacy detect code-level debt automatically: cyclomatic complexity, code duplication, dependency staleness, and coverage gaps. These tools supplement but don't replace the architectural and business-logic debt that requires human judgment to identify and document.

Most teams benefit from combining automated detection for code-level issues with a human-maintained inventory for architectural and process issues. The automated tools handle the scanning; the engineers handle the context and impact assessment that makes the inventory useful for decisions.

Labeling Conventions That Work

Whatever tool you use, consistent labeling makes the inventory searchable and sortable in the ways you'll actually need. A practical scheme includes:

Type labels: tech-debt/architectural, tech-debt/code-quality, tech-debt/security, tech-debt/dependency, tech-debt/test-coverage. These let you filter the backlog by category when planning a remediation sprint focused on one type.

Severity labels: A simple tier system works better than numerical scores for most teams. Critical (causing active problems or blocking roadmap items), High (slowing development in a frequently-touched area), Medium (known issue with low current impact), Low (good to fix eventually). The tiers don't need to be precise; they need to be consistent enough to enable rough prioritization across engineers.

Area labels: Tag items by the part of the system they affect. This lets you group debt by subsystem, which is useful when planning area-specific remediation work or when a new team takes ownership of a module and needs a debt inventory for their area.

"Technical debt conversations work best when engineering and business leadership use the same vocabulary. Most of the time, the vocabulary gap is the actual problem, not the debt itself." - Dennis Traina, founder of 137Foundry

Making the Inventory Maintainable

The most common failure mode for technical debt inventories is that they get created once and then never updated. The list grows stale, engineers stop trusting it, and it's eventually abandoned. Several practices help prevent this:

Capture during code review. When an engineer encounters debt while reviewing a pull request, they create a record immediately. The review is the natural discovery moment; the issue creation adds a few minutes if the template is ready. Making this the expected behavior changes the inventory from a project to a process.

Include debt discovery in the definition of done. When a team finishes work in a module and finds technical debt in the process, documenting it is part of completing the work item. Not optional housekeeping.

Close records when debt is resolved. An inventory that tracks only accumulation without tracking resolution gives a false picture of the debt stock. Marking records closed when the remediation work ships keeps the inventory accurate and gives the team a measurable signal that the process is working.

Codecov integrates with CI to track test coverage changes per commit, which makes it easier to close coverage-related debt records when remediation work ships rather than keeping them open indefinitely.

Using the Inventory for Prioritization and Trend Tracking

A maintained inventory enables two things that a vague mental model doesn't: productive prioritization conversations with non-technical stakeholders, and trend analysis over time.

For prioritization, apply a simple scoring model to the top items: velocity impact, risk, reach, and estimated remediation cost. Items that score high on velocity impact and low on remediation cost are the natural starting points, because they deliver visible improvements quickly and build the team's confidence in the process.

For trend analysis, the inventory shows whether your team is accumulating debt faster than it's resolving it. If the discovery rate consistently exceeds the resolution rate, the capacity allocation for debt work isn't sufficient, and the conversation with product and management needs to happen with data behind it rather than as an abstract concern.

The Agile Alliance has material on incorporating technical work into agile planning cycles, including how to make debt work visible in sprint reviews without turning every review into a technical operations briefing.

137Foundry covers the assessment and prioritization side of technical debt in depth, including the scoring model and the framework for communicating debt to non-technical stakeholders, in the full guide on assessing and prioritizing technical debt.

boardroom whiteboard charts strategy
Photo by Sora Shimazaki on Pexels

Documentation is the lowest-leverage part of the debt management process in isolation. It becomes high-leverage when it enables consistent prioritization decisions, accurate trend tracking, and shared vocabulary between engineering and the rest of the organization.

Top comments (0)