5 rules for picking long-lasting method names in OOP

When you write a piece of code for the first time, names don’t matter that much. You obviously know what everything is and what it does. However, while it’s cheap and easy to understand now, code written using poor names will grow to be incomprehensible as time passes and your application gets bigger.

The price we pay for poor names comes under many different forms: slow development speed, faulty design, bugs, and ultimately, clients and customers lost. Because of this, we should write code that is easy to understand and use now, and in the future.

A method must a query or a command. Not both.

Query methods are methods that return something without causing any side-effects. A side-effect could be anything – from updating a row in the database, to sending an e-mail, writing to a file, or posting data to an external API. Anything that changes something somewhere is a side-effect.

While query methods shouldn’t cause any side-effects, command methods should do precisely the opposite. Their purpose is to create a side-effect in your application.

Following this rule makes methods predictable. It would be awful to go into a codebase, look for a method that looks like it returns something you need, only to find out you just deleted a few hundred users in the process. Having command-like behaviour in a query can be deadly.

Query methods should be named using a noun or an adjective, while commands are active verbs.

// bad: it's named as a command but has no side-effects
$order->calculateTotal();

// better: even though it calculates something, it has no side-effects, so it should be named as a query
$order->total();

// bad: no idea what this does without inspecting it. You'd think it returns a cancellation object but you'd be wrong.
$order->orderCancellation();

// better: it changes the order state, so it’s a command that should be named with an active verb.
$order->cancel();

Avoid using “not”

Using “not” in method names might feel a tiny bit more expressive, but it’s almost always a bad idea.

Once you have an $invoice->notPaid() method, you ought to have the opposite, $invoice->paid() method. You just cannot use the double negation !$invoice->notPaid() – my brain hurts trying to make sense of it.

Adding the second paid() method will clear things up, but your application will grow to use all the possible combinations, including the “not invoice not paid” one. Some people will pick the correct method, but most will do what programmers usually do: add a not operator and be done with it.

Save yourself some pain and avoid using “not” in your method names. We already have an operator for it.

Name methods after the concept they represent

A method should allow its implementation to change without having to be renamed. To achieve this, we should name methods by what they are doing, not how they are doing it.

// bad: what if I want to change the implementation and travel by car?
public function travelByPlane() 
{
  // code to travel by plane
}

// better: it allows me to change the implementation without changing the method’s name
public function travel()
{
  // travel by plane, train, car, bike, food, crawl, anything.
}

Names describing how methods work put you in shackles. You have no choice but to change the method name or live in a lie where the method says it’s traveling by plane, but you’re actually in the street, peddling on your bike.

Name methods after the concept they represent rather than how they currently behave. A good name says what, not how.

Avoid bloated names

Good method names are usually short. If they are not, there are two reasons why.

  1. The method itself does too many things, and we need a longer, bloated name to explain ourselves. Ideally, a method should do one thing and one thing only. This being said, an even bigger mistake is to have a method doing too many things under a short name. It’s better to be explicit, and have a long name, than to sweep everything under the rug.
  2. The name includes needless information that can already be derived from the existing context.
// poor
$order->orderRefund();

// better: I'm already in a Order object
$order->refund();


// poor
$invoice->dueDateHasPassed();

// better
$invoice->overdue();

Names should be precise

Sometimes we have methods implying they do one thing but do something else. Consider the following example:

class Invoice 
{
    public function pay() 
    {
        $this->update([‘paid_at’ => Carbon::now()]);
    }
}

The method above is lying. When someone calls $invoice->pay(), no money goes into my account. What it does is, it sets the paid_at attribute to the current date. A better way to express this is by saying “it marks the invoice as being paid”.

class Invoice 
{
    public function markAsPaid() 
    {
        $this->update([‘paid_at’ => Carbon::now()]);
    }
}

The way you name things has a significant impact on the long term success and cost of your application. Investing time in choosing meaningful and precise names will reward you with steady development speed, better design, fewer bugs, and thus happy clients and customers.

Photo by Brett Jordan on Unsplash

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.