loading...

Readability for Real - Using Meaningful Names for Database Queries

alvarocavalcanti profile image Alvaro Cavalcanti ・3 min read

Readability

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 by:

alvarocavalcanti profile

Alvaro Cavalcanti

@alvarocavalcanti

Writing software about people, one story at a time since 1998.

Discussion

pic
Editor guide
 

Ideally, you also don't want to hard-code any values there in your filters. They do not scale very well.

 

I see your point, Theofanis, and it's a valid one. But just for clarification, in my context, those hard-coded values will never change. The query might get extra exclusion clauses in the future, but the definition of those plans will remain the same.

And in this case, I weighed the pros/cons for readability versus extensibility and concluded that hiding the information away in constants or even external parameters would not pay off.