Naming and Comments — Your First Line of Defense Against Technical Debt
The most effective way to keep technical debt in check isn't a refactoring sprint or a new framework — it's writing code that communicates clearly from the moment it's written.
The most effective way to keep technical debt in check isn't a refactoring sprint or a new framework. It's writing code that communicates clearly from the moment it's written.
Unclear code is debt accrued in real time. Every variable named x, every method named DoStuff, every comment that explains what the code does rather than why — these are small withdrawals from a maintainability account that will eventually overdraft. The developer who inherits that code six months later (often you) pays the interest.
At FADLtech, we hold to a simple standard: code should be understandable at a glance. That standard is achieved through three practices — communicative naming, judicious comments, and eliminating clutter.
Naming Variables
Variable names are the most frequently read artifact in a codebase. Getting them right costs nothing and pays dividends every time someone reads the code.
Compare these two lines:
var c = GetCustomer(cid);
var customer = GetCustomer(customerID);
The second version requires zero mental translation. The first forces the reader to hold c and cid in their head while scanning the surrounding code to figure out what they represent — and that cognitive overhead compounds across an entire file, an entire class, an entire system.
Names can carry even more signal when appropriate:
var goldLevelCustomer = GetCustomer(customerID);
Now the variable communicates not just the type, but the business context in which the customer was retrieved. That's the kind of detail that prevents subtle bugs when someone later modifies code that assumes all customers are treated equally.
If your team prefers brevity, agree on a standard abbreviation dictionary and enforce it consistently. cust is fine — but only if it means Customer everywhere, every time.
Naming Classes and Methods
Good method and class names turn code into readable prose. Consider this class:
public class QueueHandler
{
public static bool SendMessage(CustomerOrderMessage order)
{
// code to place a message on the queue
return true;
}
}
QueueHandler tells you what the class manages. SendMessage tells you what the method does. CustomerOrderMessage tells you what kind of message. When the call site reads QueueHandler.SendMessage(order), a developer who has never seen this code before understands it immediately.
But there's a gap: which queue? And what does true mean — that the message was valid, or that it was successfully written? The method signature leaves those questions open, and open questions become bugs.
When to Comment — and When to Refactor Instead
The instinct to add a comment is often the right one. But before writing it, ask whether the code itself can be made clearer.
Consider the ambiguous return value above. The quick fix is a comment:
// returns true if the message was successfully written to the queue
public static bool SendMessage(CustomerOrderMessage order, QueueInfo queue)
Better — and the queue ambiguity is now also fixed by moving it into the signature, which is a more durable solution than a comment. Comments go stale; method signatures are enforced by the compiler.
The deeper fix is to make the return type self-documenting:
public class SendResult
{
public bool Success { get; set; }
public string CorrelationID { get; set; }
public Exception Error { get; set; }
}
Now the return type itself communicates the contract. No comment needed, and callers get richer information when something goes wrong. In C#, named tuples offer a lighter-weight version of the same idea:
public static (bool Success, string CorrelationID, Exception Error)
SendMessage(CustomerOrderMessage order, QueueInfo queue)
{
// code to place a message on the queue
return (true, correlationID, null);
}
The named members read almost like documentation. A developer calling this method sees exactly what comes back without hunting for comments or reading the implementation. This is what we mean by "code as documentation" — the structure of the code carries the explanation, and the need for comments shrinks proportionally.
That said, comments still have a place. Complex business rules, non-obvious algorithmic choices, and workarounds for external system quirks all deserve a short explanation. The test is simple: if removing the comment would leave a reader genuinely uncertain, keep it.
Eliminating Clutter
Clutter is anything that consumes a reader's attention without adding understanding. Common forms include:
- Comments that restate what the code already clearly shows
- Variables that exist for a single use and could be inlined
- Verbose documentation comment blocks that pad three lines of boilerplate around one useful sentence
- Dead code left in place "just in case"
Each piece of clutter is a small tax on every future reader. The cumulative cost is real.
The Compounding Return
None of these practices are difficult. They don't require new tools or process changes — just attention and discipline applied consistently. Naming things well on the first pass, pausing before writing a comment to ask if the code can be clearer instead, removing noise before committing.
The developer who holds to this standard isn't just making their own life easier. They're making a deposit into the codebase that every future maintainer will draw on. That's how technical debt gets held at bay — not by periodic heroic cleanups, but by small, consistent choices made at the keyboard every day.
In future posts, we'll examine other dimensions of technical debt and how to address them systematically.