Stop using the Interface prefix in your Interfaces names!
There are only two hard things in Computer Science: cache invalidation and naming things. SPOILER: this article IS NOT about cache!
Hello, developers! 🚀
Welcome back to the Learn Agile Practices newsletter, your weekly dose of insights to power up your software development journey through Agile Technical Practices and Methodologies!
Before starting, I quickly remind you that my brand new Test-Driven Development 101 5-day Email Course is available!
With this course, you will effectively learn what TDD is, for real: what the objective of this practice is, how the TDD process works, and how it enables you to achieve better software. The course goes beyond theory with interactive quizzes and flashcards for active learning, providing practical tips and suggestions for practicing with katas.
As a subscriber to my newsletter, you can have it with a 10EUR discount!
Now, let's dive into today's micro-topic!
Why do we name things?
Giving names to things and people is one of those things we take for granted, almost like breathing - it’s a natural consequence of human beings’ communication skills.
There are multiple reasons why names help in communication, for example:
identification: it’s easier to refer to something with a name than with a description
learning and training: when we are learning something, giving names to the concepts makes it easy to repeat it; a good example is naming exercises so that they can easily be recalled and requested by the trainer without describing them every time
descriptiveness: with a name, we can instantly provide a short description - you may think this works only for things, but it’s also true for people (patronymics, for example, identify a person by his father)
I want to focus on one specific objective we should have when naming something in software: descriptiveness.
The main target we should keep in mind when deciding on a name in software is describing it properly: the name should convey just enough information to give the reader a high-level understanding of what to expect from that element.
A common mistake
One of the most common bad practices spread among software developers, one that you constantly meet in repositories, but also a lot of examples and articles online, is to use the Interface
or I
prefix/suffix in interfaces
name - and a similar issue also happens with abstract classes and the Abstract
prefix.
An example of this is having an interface
called IUserRepository
with a concrete class
named UserRepository
: IUserRepository
is already of type interface, there is completely no need to use that prefix. Also, why is this class so special to be called UserRepository? The name of a class
should describe the specificity of that specific implementation.
A better example would be to have an interface UserRepository
with a concrete class RedisUserRepository
: this is better because the interface has a generic name, and the class name tries to express the specificity of that implementation; still, the name is not ideal yet, because it’s leaking an implementation detail: the fact that the data will be written/read from Redis cache. This could be a good enough tradeoff in some cases, but we can do even more.
An even better example is to have the interface UserRepository
with a different name for the concrete class: CacheUserRepository.
We are only exposing the type of persistency we are using (cache in this case), which is the specificity of this implementation, without leaking the specific tool.
Practical tips for better names
Some quick additional mistakes to avoid are:
abbreviations: they can create misunderstanding and reduce readability
standard names/patterns: be careful with those, because if the standard is not properly shared, it might lead to misunderstanding
Both of those should be used only when they are 1part of the ubiquitous language of the team.
We can also identify some best practices to follow, instead:
Interfaces are contracts
We use an interface to describe what behaviors we expect from the classes that will implement it, in the form of methods signature; they should always have the best, descriptive name for the thing they represent a contract for: UserRepository
for the class that interacts with user data, RetrieveUser
for a query service to search for a user, SaveUser
for a command service that creates a new user, and so on.
Abstract classes are shared behavior.
We use an abstract class to create a shared baseline for a set of classes; they should always have a generic name that expresses the nature of a shared baseline without using the abstract word. A better prefix can be Base
- for example, imagine a Repository
the interface we want to use to share common patterns between our repository classes; once we have some of them, we will realize that having the same method name is not enough because most of the time we repeat some logic: we can then create, for example, an abstract implementation of the findById
method where the table name is a property/variable.
Classes names should describe the specificity
A class name should always describe the nature of its implementation and why it’s needed. Sometimes, this is easy because we are sure what’s the difference between all the implementations: for example, a Repository
interface could have an implementation to read from DB, one to read from Cache, one to read from File System - and so on. Even when we only need one, it’s easy to see this pattern and name it, for example, DatabaseRepository
.
In other cases, this is harder because we only have one implementation and there is no evidence of different implementations in the future; we still want to use interfaces to ensure dependencies are decoupled from implementation, so we need a different approach for names: I like, for example, using a prefix such as Runtime
(think to a Calculator
interface implemented from a RuntimeCalculator
).
🧠 Test Yourself in 1 minute:
💡 Did you know? An interactive activity, like quizzes or flashcards, can boost your learning!
Take advantage of our set of Flashcards dedicated to this topic: read the word and try to describe its definition - then turn the card to check the correct one for feedback 😲 Don't miss out on the opportunity to boost your learning—try now!
The main target when giving name in software is...?
Insights Recap
Naming is important for communication for multiple reasons:
identification
learning and training
descriptiveness
Descriptiveness is the main target when naming in software development: just enough information to give the reader a high-level understanding of what to expect from that piece of software.
A common mistake is to use the
Interface
orI
prefix/suffix ininterfaces
name, or theAbstract
prefix forabstract classes
. Example: aninterface
calledIUserRepository
with a concreteclass
namedUserRepository.
It’s better to give the interface the generic name and the class a name that describes its specificity. Example: an
interface UserRepository
with a concreteclass RedisUserRepository
.Even better if we don’t leak implementation details such as the tool we are using. For example,
CacheUserRepository
is a better name thanRedisUserRepository.
Do not use abbreviations, acronyms, or standard patterns unless they are part of the ubiquitous language of the team.
Best practices for names:
Interfaces are contracts: they should always have the best, descriptive name for the thing they represent a contract for.
Abstract classes are shared behavior: they should always have a generic name that expresses the nature of a shared baseline without using the
abstract
keyword, such asBase
.Classes names should describe the specificity: they should always have a name that describe the nature of their implementation.
Until next time, happy coding! 🤓👩💻👨💻
Go Deeper 🔎
Legenda
📚 Books
📩 Newsletter issues
📄 Blog posts
🎙️ Podcast episodes
🖥️ Videos
👤 Relevant people to follow
🌐 Any other content