Naming (in code) - The ultimate guide and reference

sargalias

Spyros Argalias

Posted on June 21, 2021

Naming (in code) - The ultimate guide and reference

Programming principles tell us that naming in code is important. This article aims to be a complete learner's guide for naming in code. It also aims to be a reference about naming that you can refer to in the future if you need to.

For certain things, such as naming methods, there are different naming conventions. We'll mention a few so that you're aware of how they work and the options you can choose from.

Overall, we'll examine:

  1. the motivation for wanting good names
  2. general naming tips for all code
  3. established naming conventions for specific things such as variables and classes

Motivation for good names

The motivation for good names comes from clean code and programming principles. Code should be:

  • immediately obvious and easy to understand
  • easy to change

Being easy to understand helps because:

  • code that's easy to understand will be faster to understand. This means that you can work faster. You'll spend less time trying to understand old code and more time writing new code.
  • code will be possible to understand. In comparison, if some code is difficult to understand, you may not understand it even after spending a long time reading it. Someone who's less experienced may have even worse luck. Additionally, you may misunderstand how the code works, especially if you're not fully paying attention that day. Misunderstanding code makes it very easy to create bugs.

Good names help with both cases.

How good names make code faster to understand

If something is well-named, then you don't need further details to understand it. This saves you time.

For example, consider:

  • a function named printHelloToTheScreen
  • a function named multiplyBy2
  • a constant named PI
  • a constant named MAXIMUM_ALLOWED_LOGIN_ATTEMPTS
  • a static class or module named Math
  • a variable named circumference
  • a variable named userInfo

In a codebase, you would have a pretty good idea of what those do just from the name.

How good names make code easier to understand

When reading code, you have to:

  1. read (parse) what it does
  2. understand why it does it, or rather, understand what it's trying to do conceptually

For example, it's not enough to think "this code removes initial whitespace from the string, then it sends a network request". Instead, you have to understand "this code formats the username and then sends a password reset request".

Here's a code example that's difficult to understand:

function foo(a, b) {
  const c = PI * a ** 2 * 8 / b;
  return c > 1 ? c : 1;
}
Enter fullscreen mode Exit fullscreen mode

What's the 8 there for? What's b? Why does it return a minimum of 1? What's the purpose of this function?

If you're trying to do something such as change the area, you don't know if this function is relevant or not. Even if you suspect it is, you don't know what it does or why.

Something like this would be much better:

function calculateRemainingArea(radius, reductionFactor) {
  const area = PI * radius ** 2;
  const remainingArea = area * AREA_REDUCTION_RESISTANCE / reductionFactor;
  return Math.min(remainingArea, MINIMUM_AREA);
}
Enter fullscreen mode Exit fullscreen mode

So, good names help, because they provide meaning. They help you understand what the code does and why it does it.

To get the benefit, all you have to do is give a good name to the thing.

As another example, someone may not understand PI * a ** 2. They may think "PI, a, power of 2... What the heck is that??". To make it easier, all you have to do is replace that line with const circleArea = PI * radius ** 2. It helps a lot.

General naming tips for code

In short, a good name is something that immediately tells you what something is or does. It's not surprising. It doesn't take effort to understand it. You understand it without thinking about it.

A bad name is something that you read and you wonder "what's that", or "what does that do?". Something that requires you to think more.

When writing names, they should be understandable by someone that's never seen this code before. They need to make sense, be consistent and be sufficiently descriptive.

Here are some pointers to accomplish this.

Have clear naming conventions

Your codebase should have clear conventions. This is probably the most important point in this article. If you're already following a convention, it's probably best to stick to it, even if an alternative may be more descriptive.

Conventions apply consistency. Programming principles tell us that consistency is very important.

It allows you to work faster. You can make certain assumptions about how the code works and what certain things mean. Additionally, when thinking of a name for something, the convention may already have a rule for it. This makes things easier.

Also, not following conventions can cause mistakes. You may assume that a common convention is being followed in the codebase. If you're wrong, then you may have the wrong idea about how some code works. At that point, it's very easy to create bugs.

Ideally, you should follow conventions that already exist in your programming language or framework. This makes things easier for new developers to the company. Some examples are the .NET naming guidelines and Airbnb JavaScript style guide. Otherwise, you can also create your own custom conventions for your project or company.

Prefer descriptive names

Always consider, will the next person who looks at this name understand it easily?

Use full words

Generally, full words are easier to understand. For example calculateArea or createWindow. Abbreviated words may be harder to understand. In general, avoid names like calcArea or cWin.

Avoid very short variable names

In particular, avoid single-letter or very short variables, such as d. It could mean anything: the document, data, date, or days.

The exception to this is when the name is used in a very small scope and what it represents is immediately obvious. In this case, it's easy to look one or two lines up and see where it was defined. Here's a code example using the variable e.

function sendData() { /* sends a network request */ }
function handleFormSubmission(e) {
  const formElement = e.target;
  const formData = FormData(formElement);
  sendData(formData);
}
Enter fullscreen mode Exit fullscreen mode

Here, the variable e represents the event object. We know this because the name handleFormSubmission and the function signature represent an event handler. e is only used one line under where it is defined, so it's still easy to work with.

Nevertheless, I would still personally use event. I consider readability more important than minor saving of keystrokes like that.

Another acceptable example is using i in for loops and such. That's a convention that everyone understands.

Acronyms

If an acronym is very common, then it's okay to use it. Some examples are the acronyms HTML, UI, IO, OS, JSON, XML, HTTP.

If an acronym is uncommon, then prefer the fully expanded name. If in doubt, you should probably use the full version.

Conciseness matters

Names that are sufficiently descriptive come first. However, that doesn't mean that you need super long names.

Super long names, such as a variable named integerNumberOfEnginesInObject are difficult to work with. engineCount would be sufficient.

In general, if you can have the same clarity with a shorter name, use the shorter name.

Consider the context

The name of the surrounding context can provide useful clues for the purpose of something. This means that sometimes, you can get away with using shorter names.

For example, if you have a class called Users, then the method for creating a new user can be called create. The usage of it would be something like users.create() (where users is an instance of Users). That's sufficiently descriptive. You don't need to call the method createUser in this case.

Casing

The prevalent casings in programming (excluding HTML and CSS) are pascal case, camel case and snake case. The one you use depends on the conventions for your programming language or framework.

General format of each casing

Snake casing is lower cased and uses underscores to separate words. For example this_is_snake_case.

In pascal casing, every word begins with a capital letter. For example ThisIsPascalCase.

Camel casing is similar to pascal casing, except that the first word begins with a lowercase letter. For example thisIsCamelCase.

Casing for acronyms

For acronyms, the conventions vary.

On the front end, it seems that acronyms are always fully capitalised, regardless of length. Some examples are performance.toJSON(), XMLDocument, HTMLCollection and DOMString.

However, in some other languages, such as the .NET languages, the convention is:

  • if an acronym is only two letters long, the second letter should have the same casing (upper or lower case) as the first one. For example, UIInput (pascal case), uiInput (camel case) and fooUIInput.
  • if an acronym is three letters or longer, only the first letter should be capitalised if necessary. For example JsonFoo (pascal case), jsonFoo (camel case).

Capitalisation for compound words

It's a convention to treat compound words as one word in terms of capitalisation. For example, use callback and endpoint instead of callBack and endPoint. You can find a thorough list of common compound words, used in programming, on the .NET naming guidelines on capitalisation.

Prefer semantic naming

Semantic naming means to name something after its purpose or meaning. In order of priority, this means:

  1. what the purpose of it is, or what it does
  2. how it does it

As a bonus, it also results in code that is less likely to change in the future.

When naming things, consider: what's the most important thing about the thing you're naming? What's the most suitable name for someone else to understand it conceptually?

Usually, users care more about what something is doing, rather than how it's doing it. Although, sometimes, it's the "how" that's the most important.

Here are some examples of semantic naming.

Example with a variable name

If you have a variable that holds a collection of users, the important part is that it contains users. Whether it's a list or a map is less important. Not to mention that your IDE and type declarations provide that information anyway.

Therefore, the name:

  • users would be suitable
  • userList is less preferable. The "list" part is less important than the users part. Also, if you change the data structure in the future you'll have to update the variable name.
  • userCollection is also less preferable, because the "collection" part is less important than the "user" part. However, at least you won't have to update the variable name if you change the data structure in the future.

Example with interfaces and implementations

In OOP code, you tend to have interfaces with potentially multiple implementations. An interface may be called something semantic and generic, such as Sorter, for a sorting algorithm. That's the significant thing about it, the fact that it sorts. The how isn't important at the interface level.

The different implementations can be called after the sorting algorithm they implement. That's the important thing about them and the only thing that separates them from one another. It's the information a user of that specific class would want. For example BubbleSort, MergeSort, Quicksort.

Example with a method for sorting

Imagine that you have a class containing a collection of something. You also have a method for sorting it, say, alphabetically.

If you only have one sorting method, then it would be preferable to name it sort. A name such as sortWithQuicksort or quicksort would be unnecessary information that the user doesn't care about. If you think about it, the caller of the code wants to sort. They aren't particularly interested in the specific algorithm your class uses. (The only exception is if your class is an actual bottleneck to performance or something, but that's a different topic.)

Additionally, in the future, you may change the sorting algorithm that the class uses to merge sort. In that case, the name sortWithQuicksort wouldn't make sense any more.

The solution is to name your public method sort.

The fact that you're using quicksort is still important. Developers working on the implementation of the class would want to know that. Some options for that are to have a private method named quicksort, or import and use a quicksort function from somewhere else in the codebase.

For example:

// pseudocode

class Users
{
  // the public method with a name that's useful to callers
  public User[] Sort()
  {
    return _quicksort(this.users);
  }

  // the private method with a name that's userful to someone working on this class
  private T[] _quicksort<T>(T[] items)
  {
    /* implementation of quicksort */
  }
}
Enter fullscreen mode Exit fullscreen mode

Example with front end CSS

In front end CSS, there are a few approaches. The approach you choose decides what's important about the name of your class.

When using the BEM naming convention, the important thing is the purpose of the element, not the styling. For example, you would use the CSS class page-heading instead of large-heading-red. That's because, tomorrow, the styling of the page heading may change. At that point, the non-semantic name won't make sense anymore, but the semantic name will.

If you're using a UI component library, then the styling of the component is more important than the purpose of the component. For example button-primary instead of add-to-cart-button. That's because classes like button-primary are the main ones you'll be working with throughout your code.

Other tips from Uncle Bob

Some tips that are mentioned in Uncle Bob's book Clean Code are to:

  • make meaningful distinctions. Avoid variables that seem similar or the same, such as accountInfo or accountData. A user of that code won't be able to tell the difference.
  • use pronounceable names. Names should be easy to read out loud. Some examples to avoid are names such as genymdhms and modymdhms. Better names would be generationTimestamp and modificationTimestamp.
  • use searchable names. Names should be easy to search using your code editor. Essentially, avoid names that are one or two letters long, as searching for them will return too many matches.
  • avoid using cute / offensive words. Avoid names such as whack() and seeYouLaterFiles(). Be professional and consistent.
  • pick one word per concept. For example, don't mix the words "fetch", "get" and "retrieve" for the same kind of operation throughout your codebase. Pick one of them and use it consistently.
  • avoid puns. Avoid using the same word for different concepts. For example, if in one class add() adds two numbers, in a different class add() shouldn't insert into a list.

Other tips from the .NET naming conventions

.NET makes some additional recommendations. Some of them are specifically for .NET languages. However, you may want to keep them in mind anyway.

The recommendations are to:

  • prefer naturally readable names. For example, use HorizontalAlignment instead of AlignmentHorizontal.
  • avoid using names that conflict with common keywords in other programming languages
  • prefer semantic names rather than language specific names. For example, use GetLength instead of GetInt.
  • prefer generic CLR type names instead of language-specific names. For example name a method ToInt64 instead of ToLong. That's because methods like these may be used in other CLR-compatible languages where the data type long doesn't exist. Therefore, that name won't make sense in those languages. However, Int64 exists and makes sense for all CLR languages.

Naming conventions for specific use cases

Here are some common naming conventions for things such as variables, functions, classes, etc.

Variables

Variables are just names or labels for values and objects. Some general conventions for them are that:

  • they should be nouns. For example car, user, userLocation, student, result, area, player
  • they generally use camel case or snake case, depending on your programming language

The rules change a bit for constants and variables holding Boolean values.

Constants

Some programming languages write constants fully capitalised and with snake case. This includes JavaScript, Python and Java. Some example constants are:

  • Number.EPSILON
  • Math.PI
  • NUMBER_OF_LIVES
  • MAX_ATTEMPTS_BEFORE_LOCKOUT
  • SOME_SPECIAL_VALUE

Here, "constant" refers to special values. These are values that don't depend on runtime. They could easily be placed in a configuration file, away from your application code.

"Constant" doesn't refer to a normal local variable that just happens to be immutable. Those follow the same conventions as normal variables.

Here are some examples of "constants" and "normal variables that just happen to be immutable":

  • final MAX_ATTEMPS_BEFORE_LOCKOUT = 5 (this could be in a configuration file, it's a special constant)
  • final float result = SomeClass.factorial(someNumber) (this is just a local variable that happens to be immutable. It varies at runtime depending on someNumber. It can't be placed in a configuration file)
  • const URL_ENDPOINT = '/ajax/foo' (this could be in a configuration file, it's a special constant)
  • const filteredArray = array.filter(a => !a) (this is just a local variable that happens to be immutable. It varies at runtime depending on array. It can't be placed in a configuration file)

Booleans

For variables that have Boolean values, the convention is to phrase them as a question. Start them with a predicate such as "is", "has", "had" and "can". These clearly denote that the variable holds a Boolean.

Some example Boolean variables are:

  • isValid
  • isComplete
  • isActive
  • isDisabled
  • isLoading
  • hasRan
  • hasArrived
  • hasDescendants
  • canTakeDamage
  • canDrive

In addition to being readable standalone, they read nicely in conditional statements:

if (hasLoaded) {
  doSomething();
} else {
  doSomethingElse();
}
Enter fullscreen mode Exit fullscreen mode

In comparison, if you don't use a predicate, you would use a name such as complete. This is both a verb and an adjective. It can denote a number of things. It could be a function that you run to complete something, or a variable that holds things that have already completed, or a Boolean that states whether something has completed or not, or an event name. What it represents is more ambiguous, so prefer predicates instead.

A verb like completing is slightly better. It can't denote a function, because the "ing" in "completing" means that something is already happening. It's not something that you can start running now (like a function call). However, it can still be any of the other options. Overall, it's still preferable to use predicates.

Functions

Functions are units of code that do something. Conventions for function names are that:

  • they should be verbs
  • they generally use camel case or snake case, depending on your programming language

Some example function names are:

  • createReport
  • createTodo
  • getX
  • divide
  • sendRequest

For functions that return a Boolean, a common convention is for them to start with a predicate. This is similar to variables that contain Boolean values.

Some example names for functions that return Booleans are:

  • isValid
  • hasSignedIn
  • isSignedIn
  • isFormatted
  • canDrive

Another convention I've seen is for "transformer" or "converter" functions. These are functions that convert from one thing to another. They usually begin with "to", followed by the type they're converting to.

Some examples of transformer function names are:

  • toLowerCase
  • toUpperCase
  • toArray
  • toString

Classes

Classes are units of code that contain methods and attributes.

Some conventions for classes are that:

  • they use Pascal case
  • they should be nouns (or noun phrases)

Some example class names are:

  • Observable
  • Student
  • Printer
  • Player
  • ImageSprite

General property names

In general, attributes are named similarly to variables. Methods are named similarly to functions.

However, as mentioned earlier, the name of the class provides some context.

This means that you may be able to use a less specific name for a method / attribute than you would use for the equivalent function / variable.

For example, inside a class Users, you may have a method named create. The usage of it would be something like users.create() (where users is an instance of Users), which is sufficiently descriptive.

Casing and prefixing for properties

In terms of casing and prefixes, different languages and frameworks have different conventions.

For example, the Java naming conventions mention that methods and attributes should be camel cased.

The PEP 8 Python naming convention also mentions camel casing. However, it adds that private properties should be prefixed with an underscore. For example (_privateProperty).

The C# coding conventions seem the strictest. They state that:

  • public properties should be pascal cased (for example PublicMethod or PublicVariable)
  • private or internal properties should be prefixed with underscore and be camel cased (for example private void _privateMethod)
  • private or internal static properties should be prefixed with s_ and be camel cased (for example private static foo s_workerQueue)
  • private or internal thread properties should be prefixed with t_ and be camel cased (for example private static foo t_timeSpan)

If, for whatever reason, you were creating your own convention, I would personally recommend:

  • pascal casing for methods and camel casing for attributes (this is the convention used in the Unity game engine). The reason for this is be to differentiate between Boolean attributes (such as isValid) and methods that return Booleans (such as IsValid(data)). As a second choice, I would use camel case for methods.
  • underscore prefix for non-public properties
  • possibly (not sure yet) the s and t prefixes from C# for the relevant things. As the Zen of Python says "Namespaces are one honking great idea -- let's do more of those!" (I consider prefixes to have a similar effect)

Interfaces

Names for interfaces are similar to class names. They use pascal case and are usually nouns. Sometimes they can be named with an adjective, for example "Readable".

In the book Clean Code, Uncle Bob recommends avoiding the I prefix for interfaces. The Java naming conventions recommend the same. For example interface Foo.

The C# coding conventions recommend prefixing interfaces with I. For example interface IFoo.

Personally, I have a minor preference for avoiding the prefix. That's because, as a user of the code, I'm not particularly interested on whether I'm working with an interface or a class.

Enums

The Java convention is to treat enums like classes with constants. This means to name the enum type with pascal case and the fields fully uppercase.

C# also treats them the same as classes. This means to name both the enum type and the fields using pascal case.

Personally, I prefer the Java convention because it differentiates between constants and other values.

Events, event handlers, messaging systems and commands

There are a few things to consider regarding events and their relevant functions.

Event names

Event names:

  • refer to an action
  • are normally named using verbs. For example "downloaded", "loaded", "deleted", "damaged", "moved".
  • generally use present tense for events that fire before an action starts. For example, before submitting a password reset request, you might fire an event named "passwordResetRequestSubmitting".
  • generally use past tense for events that fire after an action completes. For example, after submitting a password reset request, you might fire an event named "passwordResetRequestSubmitted".

In my experience, these conventions are common across many languages. However, there isn't much official documentation for them. One exception is with .NET, where they formally state these guidelines.

For the actual name of the event, you can use whatever makes sense to you. If your event is created in a class, the class name may provide sufficient context. For example, if you have a class Shape, you may have an event named areaChanged. The usage would be something like myShape.areaChanged += someHandler or myShape.areaChanged.subscribe(someHandler). The event name "areaChanged" is sufficiently descriptive in this case.

In terms of casing, follow the convention in your programming language. C# uses pascal casing for public members (including events). Most other languages use camel casing.

Some example event names are:

  • fileDownloading / fileDownloaded
  • userRegistering / userRegistered
  • uiElementXUpdating / uiElementXUpdated

Event handlers

For event handler functions, there are a few conventions. In front end, React tends to use the prefix "handle". C# recommends the suffix "EventHandler". Other languages may have other conventions.

Some example names of event handler functions are:

  • handleUserSubscribed / userSubscribedHandler / UserSubscribedEventHandler
  • handleFileDownloaded / fileDownloadedHandler / FileDownloadedEventHandler

My personal preference is to use the "handle" prefix. This keeps the function a verb, which is the convention for functions.

"On" functions

Functions that exist solely to raise events tend to have the name on<EventName>. For example "onAreaChanged".

One case for using these is in classes that may be derived.

Here's a C# example:

class Foo
{
  public event EventHandler FileDownloaded;

  protected virtual void OnFileDownloaded(EventArgs e)
  {
    EventHandler handler = FileDownloaded;
    if (handler != null) {
      FileDownloaded(this, e);
    }
  }

  public void Something()
  {
    OnFileDownloaded(EventArgs.Empty);
  }
}
Enter fullscreen mode Exit fullscreen mode

Here, we have a method named OnFileDownloaded whose only purpose is to raise the event.

This convention may work a bit differently in front end, but it still follows the general idea. For example, in React, you can name props something like "onClick" or "onSomeEvent". Event handler functions that you define inside a component can use the "handle" prefix.

Here's a React example:

import React from 'react';

const ParentComponent = () => {
  function handleButtonClicked() {/* do something */}
  return <ChildComponent onClick={handleButtonClicked} />;
};

const ChildComponent = ({ onClick }) => {
  const handleClick = (e) => {
    console.log("clicked");
    onClick("foo");
  };
  return <button onClick={handleClick}>Click me</button>;
};
Enter fullscreen mode Exit fullscreen mode

Here, each component creates event handler functions prefixed with "handle". The child component has the prop named "onClick". In the child component, the handleClick function calls the onClick prop.

More global message names

PubSub (message bus) and analytics have similarities to local events, but they are more global. They span a much larger area of the codebase. The can even span multiple applications (as might be the case for analytics).

With these, it's important to use more specific names, otherwise you won't know what they refer to.

A good way to do this is to use namespaces and prefixes, along with specified delimiters.

For example, with PubSub event names, you can have a namespace for the relevant area of the codebase. The format of the event name can be <areaOfCodebase>/<eventName>. For example:

  • ui/themeChanged
  • ui/fontSizeChanged
  • player/damaged
  • player/poweredUp
  • user/registering
  • user/registered
  • user/deleted

And, as explained on clean analytics by David Wells, for analytics you could use a format like <Source>:<object>_<actionName>. For example:

  • site:newsletter_subscribed
  • app:site_deployed
  • cli:user_login
  • api:site_created

These are just examples. In your own codebase, you can use as many namespaces as you want. The namespaces can be anything.

Likewise, the delimiter(s) can be anything you want. Some examples are "/", "::", ":", "_", or even no delimiter.

Commands

Commands are written similarly to functions. They are verbs in an imperative mood. They are also used in PubSub. The notes about namespaces and delimiters, mentioned above, apply to them.

Commands also usually expect a response. In other words, a command such as "CreateUser" will have a response message such as "CreateUserResult", "CreateUserSucceeded" or even "UserCreatedNotification". Overall, I'm not aware of strong conventions for these, so you can probably use whatever you like.

My personal preference for response names comes from Jimmy Bogard's post on message naming conventions. I generally append "Result", "Reply" or "Response" to the original command name.

Some example formats for command names and their namespaces are <Verb><Subject> and <subject>/<verb>. For example:

  • Possible commands are "RegisterUser" or "user/register". Possible responses are "registerUserResponse" or "user/register_result"
  • Possible commands are "DamagePlayer", "player/damage". Possible responses are "DamagePlayerResponse", "player/damage_result"

File names

For file names, you need to consider conventions for casing, as well as what to name the file based on the code it contains.

File name casing conventions and delimiters

For file naming, there are different conventions depending on the language, framework and style guide you follow.

Many conventions recommend file names that are all lower case. Words can be separated with either hyphens (-) or underscores (_). For example:

  • in HTML, the convention is all lower case, with hyphens as separators. Underscores are far less common. One reason for this is because the HTML file name may reflect in the URL (especially with older servers). Underscores in URLs are far less common than hyphens.
  • in CSS, the convention is all lower case with hyphens or underscores as separators
  • In Python, PEP 8 recommends file names to be all lower case, with underscores as separators
  • the Google JavaScript style guide recommends file names to be all lower case, with underscores or hyphens as separators

Between hyphens and underscores, you can use either. Both are acceptable. In general, I prefer to use hyphens to be consistent with my CSS classes (which conventionally use hyphens) and for the reasons mentioned for the HTML. However, if you commonly use snake case in your programming language, or if you don't write HTML and CSS, it might feel more consistent to use underscores instead of hyphens.

Some example file names are:

  • index.html, index.css, index.js
  • third-party-analytics.js
  • enemy-mover.js

Along with that, there are other conventions that recommend camel or pascal case for your files. For example:

  • C# and Java recommend naming your file the same as the main thing in your file. This means using pascal case, same as your classes and interfaces.
  • the AirBnB JavaScript style guide recommends naming your file the same thing as your default export. Again, this means using camel or pascal case, at least for your JavaScript files.
  • React takes it a step further and recommends naming all of your files consistently in each folder. For example:
    • MyComponent.js
    • MyComponent.css
    • MyComponent.test.js (test files tend to have the special extension .test.js)

So which should you choose? First, consider if one of the conventions is more common than the others for your programming language or framework. That's the natural choice. Otherwise, you can do whatever you like. My personal recommendation is to choose the naming convention that best matches the code in your files. For example, when working on the front end, the convention is for everything in your HTML and CSS to be lower case with hyphens as separators. Therefore, you might want to use that as the naming convention.

As another example, when working on React applications that use CSS modules, you might prefer to write CSS using pascal case and underscores. This makes it easier to use your CSS in your JavaScript, for example styles.Foo_bar (where Foo_bar is your CSS class), as hyphens aren't allowed in JavaScript. In this case, it may feel more natural to name your files using pascal case.

Choosing a file name based on the code it contains

In general, you want to name your file based on its purpose.

This is supported by the C# naming conventions and Java naming conventions. They state that your file name should be the same as the main thing you define in your file. For example, if you define a class Foo, your file name should be Foo.cs or Foo.java.

The AirBnB JavaScript style guide also agrees with this. It states that your file should be named after your default export. Whether or not you use default exports is a separate matter. But the point is the same. It means to name it after the purpose, or the most important thing in your file. Normally (but not always) that's thing that you would export default, if you were using export default.

One exception is if your default export is named "main", "setup" or something similar. It doesn't make sense for a file to be called "main", especially if many files have a similar default export. In that case, consider what the purpose of the file is. An alternative is to consider what the equivalent OOP code would be.

For example, consider that you have a class that deals with carousel functionality. Your OOP code would probably be a class named "Carousel". In comparison, if you write it using functions, it might look like this:

function handleChangeToNextSlide() {
  // code to change to next slide when user clicks the relevant button
}

function main() {
  // find DOM elements that are supposed to be carousels
  // set up event listeners on those elements
}

export default main;
Enter fullscreen mode Exit fullscreen mode

In the equivalent OOP code, the code in main would be in the constructor of the class Carousel. In this case, my recommendation would be to name the file carousel. That's its true purpose. Alternatively, you could also change main to setupCarousel or something and name the file after that.

As for some other cases:

  • If your file defines multiple classes: Well, most style guides would tell you to avoid files with multiple classes. Consider whether you can separate each class into its own file. Although, if you only have one public class, then that's fine. Name the file after the one public class, not the private ones.
  • If you use functions instead of classes, there might be some cases where none of the functions would suitable to export default. Again, you need to consider what the purpose of the file is. For example, if you have some functions that are used in your test files, then perhaps "test-utilities" would be a good name. Alternatively, you can consider what the equivalent OOP code would be. You would probably have a static class with static methods. Name your file after the name of that static class.

Package names and namespaces

In practice, many packages don't follow naming conventions at all. That's because a developer can upload a package with whatever name they want. There usually aren't many checks.

However, there are naming conventions for packages and for different package repositories.

Java and Maven use the format of <groupID><artifactID>. The group ID part is generally a reversed domain name. For example, if your domain is example.com, the group ID would be "com.example". It can have subgroups (additional namespaces). For example "com.example.plugins". The artifactID is the name of the jar. For example "junit" or "spring-web". In general, artifact IDs tend to be fully lower case with hyphens to separate words.

NPM (node package manager) tends to use direct package names, such as "react-dom", or prefixed with a namespace or company name, such as "@babel/preset-env". They tend to be fully lower case with hyphens to separate words.

With NuGet (package repository for .NET), the number of namespaces vary, just like with Maven and subgroups. There are many packages with a single name, such as "Moq". There are also many packages of the format <CompanyName>.<Package>, such as "AWSSDK.Core". There are also packages with many namespaces, such as "Microsoft.Extensions.FileProviders.Abstractions". If you want to follow the example of the packages released by Microsoft, then use pascal case, optionally a company prefix and as many namespaces as you need.

Namespaces (in code) seem to follow similar concepts and conventions to packages.

Final tips

Remember that naming is hard.

There are only two hard things in Computer Science: cache invalidation and naming things. - Phil Karlton

However, spending some time to come up with a reasonable name is usually worth it.

Also, as always, be pragmatic. It's okay to break these conventions once in a while. They are only here to help you make good and consistent decisions most of the time. For example, it's okay if you feel that adding the data structure to the name will help, such as userList. It's up to you to decide what's best for your project.

In addition, you probably can't spend an unreasonable amount of time coming up with good names. So, sometimes, if you've already spent too long, you might need to use the best name you've come up with so far and move on.

Overall, the most important thing from this article is that you understand the principles behind naming. In particular, that names should make the code easy to understand. If you understand that, then you'll be fine. You'll be able to come up with your own solutions and conventions even in unfamiliar situations.

Final notes

So that's it for the article. I hope that you found it useful.

If you've encountered any awful names in code you've worked on, please leave a comment with them!

Also, if you want to discuss anything, disagree with anything, or have any feedback in general, please leave a comment below.

Alright, see you next time :)

Image credits

  • Cover photo (modified) - Photo by Paul Stollery on Unsplash
  • Clear Bulb Beside White Notepad on White Surface - Photo by Burak Kebapci on Pexels
  • Green leaf with white card - Photo by Helena Hertz on Unsplash
💖 💪 🙅 🚩
sargalias
Spyros Argalias

Posted on June 21, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related