DEV Community

Cover image for Why Naming is #1 Skill for Writing Clean Code 🧼🧑‍💻

Why Naming is #1 Skill for Writing Clean Code 🧼🧑‍💻

Martin Šošić on October 11, 2023

In stories, you will often find the motif of a powerful demon that can be controlled only by knowing its true name. Once the hero finds out that na...
Collapse
 
jmfayard profile image
Jean-Michel 🕵🏻‍♂️ Fayard • Edited

Counter-argument : I don't find fetchDemographicStatsForFirstAndLastName "clean" at all.

async function fetchDemographicStatsForFirstAndLastName (
  firstName, lastName
)
Enter fullscreen mode Exit fullscreen mode

Uncle Bob acts as if there is no downside at all of using super long names
But there is a clear downside : cognitive load.

Imagine an article that was written like that.
Full of german words like PersonalEinkommenSteueerungsKommissionsMitgliedReisekostenErgänzngsRevisionsFund.

See how clean it is ?
Not.
The writer's goal is to increase the signal to noise ratio of his writing.

I strike instead to find a balance between clarity and verbosity.
Frequent words are shorter and less frequent functions longer.

The issue with first name and lastname in your example is that you are victim of primitive obsession, using strings instead of a real type.

I would refactor that to
function fetchDemographics(user) : Demograhics

Also "clean" is judgmental and nonsensical, no real code ever is clean.
Uncle Bob doesn't produce production code so for him that doesn't matter much.
But people who do should not stress out if they don't reach arbitrary levels of cleaness that don't matter to the customer anyway.

Collapse
 
raibtoffoletto profile image
Raí B. Toffoletto

Totally agree!! If I'm reviewing and see this:

fetchDemographicStatsForFirstAndLastName

it's a no go!

Naming should be meaningful but readable. There's a balance and a matter of good taste to put it in practice.

Collapse
 
davelapchuk profile image
Dave Lapchuk • Edited

Yeah I don't like that example either, but mainly because firstName and lastName are already described in the definition in the arguments. Seems redundant, especially in the age of IDEs that'll pop up the function definition or the definitions of all potential candidates as soon as you start typing it to call it.

Still, I would opt for a longer name than a comment above it any day.

Collapse
 
matijasos profile image
Matija Sosic

Interesting! I see both sides. What would be the ideal name for you? Also, I like very much the idea of using types to tell the story, if possible.

Thread Thread
 
jmfayard profile image
Jean-Michel 🕵🏻‍♂️ Fayard • Edited

What would be the ideal name for you?

The naming is ideal if it's clear for your coworkers so pull requests is the place to ask for feedback.

As a rule of thumb, I prefer to use shorter names for frequent actions and longer / more explicit names for less frequent actions.

queue.removeElementAtFirstPosition()
queue.pop()

queue.remove(7)
queue.removeElementAtPosition(7)

I like very much the idea of using types to tell the story, if possible.

Primitive obsession -> refactoring.guru/fr/smells/primiti...

Thread Thread
 
raibtoffoletto profile image
Raí B. Toffoletto • Edited

As Jean-Michel said, depends also of your coworkers culture and practices, for me a simple getDemographic or getUserDemographic will suffice. The first one is fine because it's clear that we need to pass User as an argument... but with we have several types of demographics in the app I'd go with the second.

Different cultures and languages communicate differently. In Europe for example, Mediterranean languages rely more on the context to pass the correct intent and be understood, while germanic and slavic are more about making it clear verbosely.

Same in code, for me, even the above queue.removeElementAtPosition() could have the Element dropped because it's a queue of elements... of course we are removing an element at that position.

And totally agree. Types tell you the context. I had a discussion recently with a new member in my team about adding the Async suffix to some methods in our api just because it's Microsoft's convention for c#. It's an API, everything is async by default, synchronous DB operations are the exception, so let's use the suffix for situations when we have an async and a sync methods to distinguish between them. For the rest, the type Task<> should be clear enough to indicate it's a asynchronous operation.

Thread Thread
 
matijasos profile image
Matija Sosic

amazing write up, thanks so much for sharing Rai 🙏 I completely agree, context is the king. The most important thing is that team is in sync and consistent it the naming practices they agreed upon.

Collapse
 
martinsos profile image
Martin Šošić

Author here - I agree, that might be a better name! Note that I was sticking to JavaScript here, so didn't want to use types - but I agree that if we have precise types, it can be ok to ommit that same info from name.
I use Haskell a lot these days - and there types are the name of the game. But, Haskell has no function overloading - so if you have two functions that fetch demographics, you will suffix them with some extra info about args, to differentiate them.
Soit really depends on the language:is it strictly typed, does it have function overloading, ... .

And while I agree that shorter names result in code that is easier to read quickly, practice has still shown to me that when not sure it is better to err on the longer side. It does depend on how often name is used also, as you said: but the name from my example is probably not going to be used often, it is quite specific, so I don't think making a name shorter will bring any benefits.

Your refactoring is interesting but I don't think I would go for it: it has arg "user" which is not as specific as "firstName" and "lastName", so it is not clear how is search really being done, which attributes are used to determine the people that are part of the demographic? Maybe you misunderstood and thought that we are getting demophragic data for just one person? But that doesn't make much sense because demographic is defined as statistics for a group of people.

As for "clean" being judgemental and not being realistic: I sometimes hear this argument about Uncle Bob being overly extreme in his book and not being practical, and I found so far that those who make this argument haven't really understood the essence of it. Of course there is no clear delineation between clean and non clean code, and sure, the book sometimes goes to a bit extreme lengths - but if you take the advice from it with a grain of salt and apply it, you will see a big difference, and your code will be much improved, so that is all that matters. Again, it is all about context, it depends on people, project requirements, tevhnology - a good engineer will figure out, with experience, how to apply the "clean code" to their situation with the right measure.

Collapse
 
jmfayard profile image
Jean-Michel 🕵🏻‍♂️ Fayard • Edited

Maybe you misunderstood and thought that we are getting demophragic data for just one person
Indeed, I did :)

Again, it is all about context, it depends on people, project requirements, tevhnology - a good engineer will figure out, with experience, how to apply the "clean code" to their situation with the right measure.

That's the thing, it's all context dependant but Uncle Bob delivers the same rules for everyone.
More often than not, devs end up delivering "quality" that don't matter one bit to the client.
They implement "clean architecture" because they don't want to be dirty devs.
Doing so, they loose sight that what really matters is usually not that but the time to market.
Why not both you may ask ?
If you are lucky it may work, but there is a real danger in poursuing the wrong goal.
Worse than that it often makes life worse not better for the people that are hired after them. Since programming is all about communicating with your colleagues, if you reach that point it's your failure not theirs.

Collapse
 
martinovicdev profile image
Boris Martinovic

One of the best articles I've read lately and it's a must-read for anyone. Naming things properly is one of the most important things we do.

And this isn't just important for projects that have teams around them. Think about coming back after some time on your code and you see incomprehensible names. It's such a time-waster trying to dechiper what you thought at the time.

Collapse
 
martinsos profile image
Martin Šošić

Yes exactly, I usually do it for myself first, then for others :D! Even a couple of days later, I hardly remember what I was doing -> if it wasn't for clear names I would get lost.

Collapse
 
hassankhosseini profile image
Hassan Khajeh-Hosseini

This is great, and agreed - naming goes across everything. I remember trying to come up with a name for our first startup ... and we couldn't find a good one, so finally called it 'PlanForCloud' - that name existed till we were acquired, and quickly killed hahaha

Collapse
 
martinsos profile image
Martin Šošić

Hah oh yeah, the name of the project is one thing that is the hardest to change :D. I love "Infracost" though, it is easy to remember and on point -> captures the essence ;).

Collapse
 
sreno77 profile image
Scott Reno

In addition to Clean Code by Uncle Bob, The Pragmatic Programmer is worth a read!

Collapse
 
martinsos profile image
Martin Šošić

Absolutely! My favourite is also "The Software Craftsman".

Collapse
 
georgewl profile image
George WL

I read both and personally wasn't keen

Uncle Bob especially, dude broke his own rules in his examples, and just wasn't consistent at all in what he was saying.

Collapse
 
jordantylerburchett profile image
Jordan Tyler Burchett

This is a great article! I've always named variables and functions based on what they do and it makes code a lot easier to understand but something I noticed about myself was that I would do this but still over comment..

Commenting is important but it doesn't have to be extensive. If you write clean code it will speak for itself.

Collapse
 
artxe2 profile image
Yeom suyun

you can't give a good name if you don't have clean code behind it.

I completely agree with your statement.
Personally, I would also like to emphasize the importance of accurate indentation and file separation in addition to these points.
In the case of bun, the number of lines in a single file exceeded 20,000.

Collapse
 
ivosluganovic profile image
Ivo Sluganovic • Edited

Absolutely love this article, and could not agree more!
I was literally discussing some of the same points with a friend yesterday :)

Essentially, if someone names their code properly, it's beautiful and typically easy to follow; as you also stated, the main reason being that writing clean and good code is a prerequisite to good naming. And such code is easier to understand.
The converse is also typically true -- if code was named recklessly, ... good luck in understanding it.

Since I've been thinking about this quite a lot, here a tidbit of my reasoning related to self-descriptive vs non-descriptive names:


MORE GENERALLY, giving an idea (e.g. a system component/server/etc) a name is crucial because it makes it immediately possible for everyone to think about it in bounded terms (as long as we have a shared understanding of it basic meaning, we will all mostly agree what you mean when you mention X, or agree on whether Y is part of X or not, etc.).
This was nicely emphasized in Orwel's 1984 and its Newspeak: if you don't have a shared name for a concept (or are forbidden from using it, like protest in 1984), then it is very hard to plan/collaborate because you need to be providing the idea's boundaries and description every time: "let's go to the main square and cause a bit of upheaval and raise attention to our cause, but not too much so that it does not become dangerous", rather than simply say "let's go and protest".


HOWEVER, as much as I love (and typically use) self-describing names in code (no need for comments/less documentation!), it is actually often beneficial to name certain types of entities closer to how we name children: use names which are disconnected from their characteristics (as those are not known at creation time :D).
This is typically true with ideas whose names are hard to change (e.g. companies!), but whose functionality evolves.

Using nondescriptive names like "fluffy", "lookingGlasss", "Armadillo", "Beast", essentially creates a layer of indirection/mapping that allows us to gracefully extend/change change their characteristics/behavior/responsibilities with time by simply updating the documentation to take the changes into account.
Otherwise, we end up in a typical situation where each name has a caveat about "historical reasons why it is indeed called ProxyServer, but that name is long deprecated,it actually also does A, B, C and D".

Collapse
 
martinsos profile image
Martin Šošić

That is an interesting take and makes perfect sense to me, thanks for sharing!
I guess this would be for bigger sub-systems, where as you said, the role of it may change to some degree with time, and it is not yet clear what it is going to be exactly.

I agree that for common concepts it is good to have short names. And it works, because we assume everybody working on project will have to learn what those stand for, and in return we get easier naming / reading / talking about them. In the current project I am working on (Wasp), we have such names: Entity, Analyzer, Generator, Operation, ... -> these do require context to be understood, but they are so widely used and central to the whole project that these short names work fine.

Collapse
 
georgewl profile image
George WL

I love your inclusion of cartoons, really adds to it

Collapse
 
tonilastre profile image
Toni

Great article! 100% agree with everything here! Naming (and structure) is what makes your code clean so it is easy to get back and continue working when you need to, same with having a tidy clean room or workstation.
Whenever I need to add comments to my code, I always stop with it and think about a better naming instead.

I also use specific rules for naming variables, e.g. dates and timestamps always end with <name>At (createdAt, lastModifiedAt), maps are always <key>By<value>, (e.g. personById, titleByCode), sets have prefix unique<x>, booleans start with is<x>, has<x>, etc.

Collapse
 
martinsos profile image
Martin Šošić

Thanks, love those prefixes/suffixes! I listed only a couple of them, but I also use stuff very similar to what you described, especially the thing for maps / grouping "By".
I think it would be very interesting to add more examples to the article but it started feeling very long at some point.

Collapse
 
matijasos profile image
Matija Sosic • Edited

it would be nice to produce some kind of naming cheatsheet / styleguide that people can refer to and fork

Collapse
 
llxd profile image
Lucas Lima do Nascimento

Such a nice article!

Creating names is a big part of the reason I like TailwindCSS so much by the way.

It takes a lot of effort coming with reasonable and good names everytime. Having this weight lifted off your shoulders at least for CSS classes is pure relief.

Good job, @martinsos!

Collapse
 
matijasos profile image
Matija Sosic

+1 on this, the best thing with Tailwind is not having to invent names - that's an amazing point Lucas :)

Collapse
 
korenmiklos profile image
Miklós Koren

Great article. Some of the recommendations are language-specific, though.

I am still getting used to the fact that, in Julia, being a language with multiple dispatch, the best function name is usually a short word. For example, mean(A::AbstactArray) is expected to compute the arithmetic average, whereas mean(d::UnivariateDistribution) provides the theoretical expected value of a distribution.

Collapse
 
sodic profile image
Filip Sodić • Edited

Great Article!

Just for fun, here's some more examples of less-than-ideal names and misnomers in the tech world:

  • AJAX (Asynchronous JavaScript And XML) - Despite being in its name, AJAX rarely involves XML these days.
  • double - A ridiculous way to call numeric datatypes, but we're all used to it (float is not the best name either).
  • JSON (Java Script Object Notation) - While not necessarily a bad name, it can be a bit misleading. JSON has expanded beyond the realm of JavaScript, making the 'JS' part of its name a little confusing.
  • Go (the programming language) - A name so difficult to search for that it's spawned an alias people use when talking about it online (golang).

That's all I can remember for now! :D

Collapse
 
martinsos profile image
Martin Šošić

Love it!

Collapse
 
infomiho profile image
Mihovil Ilakovac

Great article! Typical parents, getting you the thing they think you need 😂

Pieces of this article would make for some great Twitter threads and probably start some interesting discussions.

Collapse
 
bbkr profile image
Paweł bbkr Pabian • Edited

In Raku language there is a feature that makes names super consistent across whole codebase by sheer force of laziness. Like this:

my $person = 'John';

sub greet ( :$person ) {
    say 'Hi' ~ $person;
};

greet( :$person );
Enter fullscreen mode Exit fullscreen mode
  • In greet function signature :$person means it is expecting named param called 'person'.
  • Raku is fully MOP, so variable knows its name. This self-awareness can be used in function call, where :$person in a syntactis sugar for person => $person.
  • Also providing eye-pleasing symmetry between function signature and function call.

You may ask - what is the big deal?

Well, if you can write less by simply aligning your naming with function interface - you will intuitively do that both ways. Define matching variable names when having function and define matching function signatures when having variables. You will immediately spot misalignments like:

my $username = ...;
my $password = ...;

login( user => $username, pass => $password );
Enter fullscreen mode Exit fullscreen mode

This ability to use variable as named param if name matches is by far my favourite feature of Raku.

BTW: "Clean Code" by Robert Martin is indeed an excellent book.

Collapse
 
thenickest profile image
TheNickest

Nice article and discussions here and I agree with some readers: the chosen name seems overly long. Would be unnecessary for me to add first and last name to the function name. Other than that I‘d always opt for balance between clarity and verbosity. With slightly more comfort on the clarity side. Comments I completely neglect until it becomes inevitable to use them.

Collapse
 
matijasos profile image
Matija Sosic

This might easily be the best article I've ever read on programming :).

Collapse
 
angelotheman profile image
Angel Oduro-Temeng Twumasi

Hey, this was a good read.

Do you think I could also write for Wasp?

Collapse
 
matijasos profile image
Matija Sosic

Hey Angel, join our Discord at discord.gg/rzdnErX and ping us there!

Collapse
 
angelotheman profile image
Angel Oduro-Temeng Twumasi

Right away. I am grateful for the opportunity to do so. Check out my articles as well and let me know your thoughts 🥂

Collapse
 
vincanger profile image
vincanger

dang! I had never considered some of the points before. learned a lot

Collapse
 
ivanignatiev profile image
Ivan Ignatiev

Last time, I often ask ChatGPT for variable or function names.

Collapse
 
martinsos profile image
Martin Šošić

That's a good idea! How does that work out for you? I guess one thing it is missing is a wider context though?

Collapse
 
ivanignatiev profile image
Ivan Ignatiev

The context can be provided to ChatGPT with links to a documentation or GitHub Copilot X can be used on a whole code database.

Simple example:

Image description

Collapse
 
ivanignatiev profile image
Ivan Ignatiev

You can even try to improve you ugly code:

Image description

Collapse
 
marcitpro profile image
Marcitpro

Code cleanliness is extremely important.

Collapse
 
inversematter profile image
Erik

Great article, I especially liked the part on what is a good name. It reminded me of the classic: Long Names Are Long.