Better naming convention

In the last couple of months, I spent a lot of time studying Proophessor Do demo project that showcases features of Prooph components, all with the aim of mastering CQRS/Event Sourcing concepts. Along the way, something else turned my attention away from the main topic - unconventional, but clean and concise naming convention for class and method names.

This was a true eye-opener for me, I immediately liked the idea and after adapting it a bit I started practicing it at work. Excited and full of enthusiasm, I shared my findings and opinions with the rest of the world:

Later I found out that Doctrine Coding Standard project is also enforcing many of these conventions which gave me confidence that I'm going in the right direction because parts of the community have already adopted such naming style.

I feel like I only scratched the surface with my tweet that opened many questions, without detailed explanation and reasoning behind the ideas presented. This post aims to fix that.

In order to understand what is good about this approach, we first need to understand what is wrong with the conventional one. Following are several naming conventions which I formulated as naming anti-patterns for reason. They are the motivation for designing a new, better naming convention.

Anti-pattern 1: Prefixes/suffixes convention for Interfaces

Let's start with the one for which there should be the least controversy. To give you better a sense of the problem, I'll make an analogy with one feature of human language - tautology:

In literary criticism and rhetoric, a tautology is a statement which repeats the same idea, using near-synonymous morphemes, words, or phrases, that is, "saying the same thing twice"

More at Wikipedia

Tautologies are common in everyday language, and when unintentional, they are often considered a fault of style. Think of terms such as "round circle", "dry desert", "new innovation". Sometimes even acronyms are not spared of this: "ATM machine", "GPS system", "ISBN number".

Now consider this piece of code and read aloud the entire definition of this interface:

interface TodoRepositoryInterface
{
}

Exactly, tautology is present in programming, too. Until recently, I did not pay attention to that, I did not think about this at all. Now I realize that this imposed naming convention is as silly as using TodoClass instead of Todo for the name of the entity class. Here's why I believe so:

  1. Interfaces already have the keyword interface in their definition, and therefore using I as a prefix or Interface as a suffix is a tautology that does not provide any additional value, but only blurs the actual purpose.
  2. Each of these meaningless prefix/suffix naming conventions violates the DRY software development principle as well.
  3. UML class diagrams provide mechanisms to represent and distinguish classes, interfaces («interface» preceding the name) and abstract classes (italicized):
  4. Modern IDEs are doing a similar thing by visualizing files:

The same arguments apply to abstract classes and traits, and respective Abstract and Trait prefixes/suffixes. However, since abstract classes should never be part of any public facing interface (consumers will deal with interfaces, value objects, entities), I think that Abstract prefix is somewhat acceptable exception to the rule. Of course, you could still come up with a better name by using alternative prefix such as Base. Yet, this should be used as a last resort, because I assure you that you can get the right name if you precisely describe purpose and scope of the abstract class. For example, PdoRepository could be an abstract class with logic common for PDO-based repositories, while MySqlTodoRepository could be a concrete implementation.

Something that is not so common in PHP, and I hope it never will be, is practice of using Impl as a suffix for concrete implementations. That is even more noise, more tautology, because anything that isn't an interface is basically an implementation, so putting Impl suffix on every name of every class is absurd to say the least.

It is quite clear that language construct prefixes and suffixes do not bring any value, and they add nothing but more stuff to type to your code.

Anti-pattern 2: Archetype suffix convention for domain classes

What I'm focusing on here are classes that make up the domain, core business logic of the application - Entities, Value Objects, Exceptions, Events, and similar. Entities and Value Object are the least controversial, because we are all more or less used to choose a good name for them: User, EmailAddress, Todo, TodoText. But let's examine following Exception class that represents an exceptional condition in our domain:

namespace My\Todo\Exception;

final class CannotReopenTodoException extends \Exception
{
}

Reading it, Exception suffix is not nearly as striking as in the case of Interface suffix. Things start to change when you look into FQCN: \My\Todo\Exception\CannotReopenTodoException because Exception is already a namespace. But even if we ignore the repetition within the FQCN, CannotReopenTodoException it is still a form of tautology, because wording and the context in which it is used (throw, catch, $ex variable name) unambiguously indicate that we are dealing with an Exception:

try {
    throw CannotReopenTodoException::notDone($todo);
} catch (CannotReopenTodoException $ex) {
}

It should now be clear that the suffix here is superfluous.

Event is another concept that is an indispensable part of event-driven and event-sourced architectures, and the same principle applies for them and most of the other domain elements that resides in their own namespace. The importance of the wording is even more pronounced in their case. FooEvent does require suffix for clarification, but accurate description told in the past tense such as TodoWasMarkedAsDone is self-evident.

Suffix removal is possible only if the class names are descriptive enough. Bad name is usually the result of a design flaw, and the inability to rename a class to something meaningful suggests that it has a poor cohesion.

Anti-pattern 3: "get" prefix convention for property accessors

Enough with tautologies. The claim that get prefix is excessive is a bold statement, and it seems to be the one that is very hard to swallow for a lot of people who have read and discussed my tweet.

Getters and setters are the main forms of interaction with the properties of an object through its public interface. But given that Value objects are immutable, and Entities foster encapsulation, there should be no classical setter methods in any of them. In such circumstances, the getters take on the role of simple property accessors:

final class Todo
{
    public function getId(): TodoId
    {
    }

    public function getDescription(): string
    {
    }

    public function getStatus(): Status
    {
    }
}

It becomes obvious that the get prefix becomes excessive and provides no value to the consumer other than grouping all the property accessors with a common prefix.

I believe that the alternative "strip naked" naming convention for property accessor methods is a step closer to what will soon be a standard way of writing entities and value objects. Since the Typed Properties RFC has been accepted and feature will be available in PHP 7.4, and hopefully Read-only Properties RFC will go equally well, in the near future we will be able write our classes as follows:

final class Todo
{
    public TodoId readonly $id;

    public string readonly $description;

    public Status readonly $status;
}

Final thoughts

I regret that it took me a long time to start thinking pragmatically about naming, because now most of my projects, both private and open source, still suffer from this tautology syndrome and the majority will never be healed. But going forward, every new work and new backward incompatible versions of my libraries shall be in accordance with the naming style elaborated in this article.

TL;DR


convention naming tautology anti-pattern