There are only two hard things in Computer Science: cache invalidation and naming things.
Phil Karlton reportedly came up with this line during his time at Netscape, in the late 90s, and it has stayed one of the most popular programming jokes ever since.
A common trait of successful jokes and comedy is that they reveal some surprising truth, in a witty way. In fact, I even believe that laughing is something we developed, as human beings, to show appreciation towards others’ brilliance — but I digress.
So if that programming joke got so popular, it’s because it’s true in some way.
Leaving aside cache invalidation for today, during my career, naming things well has been indeed very hard, and very often.
I believe the hardship comes from two factors:
⬆️ High importance — good names are important for a surprisingly long list of deep reasons, from software to communication.
⬇️ Low consensus — there is surprisingly little out there about how to name things in software. If you search for resources and articles (as I did), most advice focuses on low level rules about basic hygiene, like using snake_case or camelCase, or starting boolean vars with
is
orhas
. Well, that’s not what makes naming hard.
So, as always, let’s address this from first principles, and move top-down from them.
This article is a collection of ideas, mental models, and tactics that have served me well over more than 10 years. It is bound to be controversial and you may not agree with what I say, but even if you disagree with most of it, if it makes you think more about this subject while doing so, I consider it a win!
So here is what we will cover today:
💬 Names matter — why good names go a long way, and why bad ones are worse than you think.
📡 Systems and services — naming strategies for your big architecture pieces, and the feud between clever and descriptive names.
📂 Folder structures / architectures — discussing discoverability, using context, and a critique of the screaming architecture.
🔧 Naming classes and functions — discussing nouns, verbs, prefixes, and grep-ability.
📊 Keeping consistency — good rules are only half of the job.
Let’s dive in!
💬 Names matter
When you think about it, naming things is hard only because we care about it. But why should we?
When I was studying CS at university, I remember going through the GoF design patterns. One of the main benefits of patterns is that they build a shared language through which we can describe complex ideas with simple words. Today, if I say I need a proxy, a singleton, or an adapter, most engineers understand what I mean (I hope!).
So, names are vectors of meaning.
They are like mini abstractions: done right, they label concepts to simplify work and communication. Done wrong, they hold you back, confuse people, and make your work inflexible.
This is true at all levels and works like a fractal: from the Ubiquitous Language you develop for your domain, down to the conventions you set for naming methods.
So let’s go top-down, starting with how to name the big guns of your architecture 👇
📡 Systems and services
I have created separate chapters for naming strategies based on the level of granularity of your pieces of software.
This wasn’t the original plan, but while I was writing this article I realized that my ideas about naming e.g. systems were different—sometimes radically—from those about e.g. classes and functions.
One area where I am conflicted is the feud between clever names vs descriptive names:
💡 Clever names — names that are either wordplays, or character names, or else, that have some indirect relation (or not!) to what they refer to. E.g. Dropbox’s feature flag service is called Gandalf, because “thou shall not pass”.
✏️ Descriptive names — names that explicitly indicate what something is doing. E.g. replacing Gandalf with a more mundane FeatureFlagService.
Most advice out there tells you to avoid clever names and always us descriptive ones. I found this true for individual classes, components, and (of course) methods, but not necessarily for services.
1) Clever names 💡
Naming systems and services feels different from naming stuff inside code.
One reason might be that services are singletons: e.g. there is exactly one auth system at any given time, or one feature flag service.
When stuff is individual and doesn’t follow a pattern, there is no point in using conventions. Putting “Service” at the end of “FeatureFlagService” doesn’t tell me much about other services.
Also, descriptive names invariably reduce your design space. After naming your service FeatureFlagService, it becomes difficult to evolve it into anything else, such as running A/B tests for marketing or handling access control for features. Although technically possible, the original service would then feel misnamed.
Conversely, I will probably remember that Dropbox’s feature flags were handled by Gandalf until I die.
Radoslav Stankov, former CTO at Angry Building and ex Head of Engineering at Product Hunt, gave me his take on this: