Readability for Real - Using Meaningful Names for Database Queries
Alvaro Cavalcanti
Posted on October 16, 2018
Readability matters
Anyone that has programmed for a while and had to deal with someone else's code knows it (especially when this someone is yourself, six months ago). It can be frustrating to try to understand a seemingly innocent bunch of lines of code, but end up thinking "what was this person thinking back then?".
I have come across a scenario similar to the one below, which I managed to have its obscure business rules exposed into the code without the use of comments. You see, I am strongly against using comments. For me, they should be used as a last resort, with maintainability as the main argument for this. We all know how easily comments can get out of synch with the code.
Scenario Description
Imagine you have a subscription-based business, where your customers sign up to different plans, which can be billed monthly or annually. This system has been running for a couple of years now and you need to perform some batch process to subscriptions six hours before they get renewed. But this should not be for all plans, you need to exclude the subscriptions to "Partner Plus" plans, both annually and monthly recurrences.
At first, it may seem simple, but the reality is that during the past years things evolved rather freely and you don't have a simple ID for each plan. In fact, the whole concept of what is a "Partner Plus" plan depends on different things. The plan's name should have "partner" on it, but it's not limited to that alone: "partner agile expo 15", "partner plus", "new partner plus", etc. Also, the price is variable, but at least is always greater than 249.00 for monthly and 2490.00 for annually.
Writing the Code
With that in mind, you might end up with a code similar to this (it's a Python code for a Django application):
subscriptions = Subscription.objects.filter(
period_end__lte=datetime.now(timezone.utc) + timedelta(hours=6),
active=True,
).exclude(
"plan__plan_id__contains": "partner",
"plan__recurrence": "MONTHLY",
"plan__price__gt": Decimal('249.00')
).exclude(
"plan__plan_id__contains": "partner",
"plan__recurrence": "ANNUALLY",
"plan__price__gt": Decimal('2490.00')
)
Well, based on what I described earlier this code does the job beautifully. It looks ahead six hours, and excludes the plans that match the Partner Plus definition, right?
But, what if six months from now a new team member is tasked to change this code. Will she be able to understand why that exclusion is being done? And what kind of objects are being excluded? Most probably she would need to ask around a bit.
But now have a look on this refactored code:
next_6_hours = datetime.now(timezone.utc) + timedelta(hours=6)
partner_plus_monthly = {
"plan__plan_id__contains": "partner",
"plan__recurrence": "MONTHLY",
"plan__price__gt": Decimal('249.00')
}
partner_plus_annually = {
"plan__plan_id__contains": "partner",
"plan__recurrence": "ANNUALLY",
"plan__price__gt": Decimal('2490.00')
}
subscriptions = Subscription.objects.filter(
period_end__lte=next_6_hours,
active=True,
).exclude(
**partner_plus_monthly
).exclude(
**partner_plus_annually
)
Now the variables bear the context, and even if the new team member does not get it completely, at least she can be more informed when asking around, she can start off with "why do we need to exclude partner plus plans from this query?".
The thing with readability-driven refactorings is that they tend to be overlooked due to the seemingly "low impact", because, you know, "it's almost the same code", "everyone in the team knows what it means", "a comment line would do it", etc.
Well, to that I say: challenge yourself! Writing is about communication. Either writing prose or code!
It's Dangerous to go Alone, Take This
Before you go, I'm gonna leave the following link here (and in all my future readability articles) because it was the one article which opened my mind on the matter and I keep coming back to it every now and then: FunctionLength, by Martin Fowler
Posted on October 16, 2018
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.