How to Make Your Code More Readable
When I was in high school, I had a tendency to procrastinate when it came to assignments and, well, pretty much everything in life. I think that this is sort of a staple of the teenage condition. As a result, I’d often stay up late writing some paper the night before it was due and turn it in.
Working my way through life, I became less of a procrastinator and started to complete tasks on or ahead of schedule and without heroic all-night efforts at the 11th hour. This gave rise to a situation in which I’d frequently have something finished but not turned in for days or even weeks. And I discovered an interesting consequence of this situation–re-reading a paper or presentation with some time had elapsed allowed me to read the paper almost as if someone else had written it. To put it a more computer-science-y way, it nudged me off of the happy path of thinking “of course all of this phrasing makes sense exactly as is, or I wouldn’t have written it.”
Of late, I’ve been steadily working two or three projects and dividing my time up on a per-day basis to still allow myself to get in “the flow.” That is, I spend Monday on project A, Tuesday on project B, Wednesday back on A, and Thursday on C, for instance. The actual number of days and motivation for switching varies, but you get the idea. And like my improved work ethic in school as I grew up, I’ve noticed an interesting consequence: more readable code.
What seems to happen is that I get into a sweet spot between unconscious familiarity and complete lack of insight with the code. Enough time has elapsed since I last looked at it that I don’t simply take it for granted and see without looking, but not enough time has elapsed that I have no idea what’s going on. To illustrate what I mean, consider the following gist (modified from actual code that I was writing for the sake of anonymizing):
public class SomeClass
{
private readonly List _cusotomers = new List();
public void AddToQueue(CustomerModel cm)
{
if (cm.IsActive && !_cusotomers.Any(c => c.Name == cm.Name))
_cusotomers.Add(new Customer() { Name = cm.Name });
}
}
As I write code these days, I rely increasingly on various refactorings during the course of TDD: extract method, extract local variable, add to new class, declare type, etc. In this case, during a refactor cycle, I had extracted the method “AddToQueue” from another method where the “CustomerModel” argument had been a very tightly scoped local variable, such as the “c” variable in the “Any()” call. The result is a method that’s nicely short in scope, but suffers from some naming and semantics that tend to hide a bit about what this method is actually doing. If I’m going to put my money where my mouth is in my various posts deriding comments, I need to do better when it comes to making code self-documenting.
What could be improved here? Well, for starters, the name of the method is a little misleading since the result isn’t always an add. Secondly, what is “cm”? And, if you’ll notice, there’s a typo in the “customers” field–not particularly important, but sloppy. In short, this could use a bit of tightening up–a bit of editing for readability, if you will. How about this:
public class SomeClass
{
private readonly List _customers = new List();
public void AddCustomerForModelIfValid(CustomerModel modelOfCustomer)
{
if (IsModelValidForAdding(modelOfCustomer))
AddCustomerForModel(modelOfCustomer);
}
private bool IsModelValidForAdding(CustomerModel modelOfCustomer)
{
return modelOfCustomer.IsActive && !_customers.Any(c => c.Name == modelOfCustomer.Name);
}
private void AddCustomerForModel(CustomerModel modelOfCustomer)
{
var customerBasedOnModel = new Customer()
{
Name = modelOfCustomer.Name
};
_customers.Add(customerBasedOnModel);
}
}
I don’t know about you, but I’d say the latter version is a lot clearer. In fact, I think it’s so clear with the naming of variables and methods that adding comments would just be awkward. While the first one wasn’t terrible (it’s hard to be too confusing with methods that short), it definitely left something to be desired in the “self-documenting” category. The latter, I’d say, gets there.
The “sweet spot” that I mentioned earlier is the best time to make that kind of thing happen. It’s a little cumbersome in the middle of a refactoring to stop and say, “okay, let’s focus on naming and spelling.” That’s sure to interrupt your flow. But let that code sit for, say, four to seven days, and then give it another look. If you find yourself mumbling things like “what’s cm… oh, that’s right,” then you can be pretty sure others will mumble that as well, but without the “that’s right.” Don’t let that moment slip away–it’s an opportunity that only happens when you read your code a few days after the fact. Use it to fix the code right then and there when you’re reading for understanding instead of creating. You won’t regret it, and maintainers of your code will thank you.