Skip to content

Instantly share code, notes, and snippets.

@IwoHerka
Last active April 1, 2024 15:39
Show Gist options
  • Star 22 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save IwoHerka/a254cbfb2fadba5f240e68a16fc36c89 to your computer and use it in GitHub Desktop.
Save IwoHerka/a254cbfb2fadba5f240e68a16fc36c89 to your computer and use it in GitHub Desktop.
Naming Guidelines

Naming guidelines

1. Syntax

1.1 Be consistent

Consistency in naming makes reading and memory retrieval much, much easier. Conversely, changing rules and mixing conventions are very confusing and significantly increase cognitive load. Follow language, company, and project conventions for names, even if you don't like them.

1.2 Follow conventions

Most programming languages have stylistic conventions for writing names - if not official, most communities provide their own. Use language-specific code linters to check the code.

1.3 Use dictionary words

Only use words and abbreviations that are in the dictionary. Use abbreviations and acronyms only if everyone knows what they mean. Make exceptions for abbreviations such as id and other well-known or documented domain-specific abbreviations. Names can become confusing if spelling errors are made, especially inconsistently. In general, abbreviations, if not well-known, add further ambiguity.

  • Avoid neologisms and slang.

    Use existing, well-known names, especially if your team is not all native English speakers.

  • Avoid letter-only names.

    Especially single-letter names. Yes, this counts for loops too. Unless you're using C, there is little reason for using manual loops anyway, as most languages support functional iteration.

    for (Element element : elements) {
    	...
    }
    
    for (int i = 0; i < elements.size; i++) {
    	val element = elements[i];
    	...
    }
  • Avoid esoteric abbreviations and acronyms.

    Especially arbitrary ones you too will forger in five minutes. Example:

     while(i_love_lucy_is_on_tv)
     {
         xqtc_fn();
     }

1.4 Make names pronounceable

This will make it easier for your brain to remember them.

  • Avoid special symbols.

    Make exception for _ in snake case and other special conventions. For example, >=> and <*> are valid function identifiers in Scala, colloquially named fish and space ship. In Clojure, -> function is a well-known "thread-first" macro (together with =>, "thread-last" macro").

  • Only use underscores between words (and other symbols).

    Example violation: _ans_var_question_05 or trivWndFeedback_.

  • Only use one underscore at a time.

    Exception: In Python, double underscore indicates special method defined by the Python language, e.g. __init__.

1.5 Keep length within reasonable bounds

No hard rules here; use your good judgement. In general:

  • Prefer full-words over abbreviations.

  • Limit name word count (<= 4). Avoid unnecessary context and keep your name length to a maximum of four words. Names should be limited to the maximum number of words people can read at a glance.

  • Limit character length. Keep name length within 20 characters.

  • Non-reducible longer length name marks a problem in technical design in most cases. For example:

     isCurrentSquareNextToAtLeastOneBlockedSquare(currentSquare)
     // could be moved into a method (if using OOP):
     currentSquare.nextToBlockedSquare()

1.6 Make sure names are hard to mix up

  • Make names differ phonetically.

    Example: data_earth and date_of_birth.

  • Make names differ by more than word order.

    For example, employeeCount and countEmployees in the same lexical context would be very easy to mix up.

  • Don't shadow existing names.

  • Avoid numeric suffixes. Do not add numbers to multiple identifiers that share the same base name, e.g:

    val employee1 = convert(employee)
    val employee2 = convertSomeMore(employee1)

1.7 Name constant values

Don't rewrite a value as a name; name what the value represents. Replace number names with either domain-specific terms, such as PI, or a name that describes the concept that the number represents, such as BOILING_POINT. However, don't define constants for values which don't have names and/or are not special:

#define ONE_THIRD 0.25

2 Semantics

Make sure that a name is not:

  • too specific
    • overspecifying/leaking implementation
    • too long or consisting of too many words to read at a glance
  • too ambiguous
    • expressing a too generic concept
    • being a homonym (having multiple meanings)
    • an abbreviation that is unobvious to a junior
  • incorrect, i.e. expressing the wrong concept
  • inconsistent, i.e. expressing an already-named concept using a different name.

2.1 Express meaning

  • Use large vocabulary to avoid homonyms and synonyms.

    file can be replaced with filename, filepath, fileContents or fileHandle, according to it's specific meaning. If you're trying to express the concept of "perimeter", use identifier perimeter instead of boundary.

  • At the same time, make sure you're consistent in your naming and not using too exoteric words, especially if the team is not speaking English natively.

  • Use problem domain terms.

    Prefer terms which relate to the problem the software is solving or that the client is using.

2.2 Avoid ambiguity

  • Be specific.

    Avoid abstract and generic words like it, everything, data, handle, stuff, do, routine, perform. Examples:

     func_1()
     handle_data()
     do_args_method()
  • Abbreviate with care.

    As a rule of thumb, if you're not sure if a junior in your team knows particular abbreviation, it's a good idea to skip it. Also, watch whether the abbreviation is ambigous. Examples:

     e // for error, event or element
     cx // count of x
     f // for flag
     nbr // for number
     tbl // for table
  • Use standard, neutral language.

    kill is better than dispatch or slay.

  • Use positive Boolean names.

    Prefer isEnabled over isNotDisabled.

  • Use stanard opposite pairs

    Typical pairs include add/remove, begin/end, create/destroy, destination/source, first/last, get/release, increment/decrement, insert/delete, lock/unlock, minimum/maximum, next/previous, old/new, old/new, open/close, put/get,show/hide, source/destination, start/stop, target/source, and up/down.

  • Make names differ in meaning

    Names like input and inputValue, and recordCount and numberOfRecords can be easily confused if used in the same lexical context:

     val recordCount = ...
     ...
     val numberOfRecords = ... // Huh? We have this already

2.2 Don't leak implementation

The name should express precisely what needs to be understood by the reader, nothing more. Avoid overspecifying meaning; treat names as kind-of generic interfaces - boil down the essence of what something is, identify and remove all that is not essential or can change. Leaking implementation is bad because it increases noise in the code and the coupling between different objects (in this case, between statements or expressions that use an overspecified term).

  • Keep name's meaning relevant to the semantics in its immediate context, nothing more. For example, if you're working with in-memory key-value database such as Redis, then probably your business logic shouldn't know all the details about its client object, such as that it is in-memory or Redis specficially. Then the keyValueStore would be a better name than inMemoryKeyValueStore or redisClient.

  • Omit type information, except for is prefix for Booleans. Generally, it's a good idea to avoid Hungarian like notations which leak the type of object, but the problem with Booleans such as isActive is that "active" on its own can be confused with an adjective with an implied noun - "active something" instead of "is something active?". Booleans don't generally change types to non-Booleans, so it's a safer and more readable option.

2.3 Ensure semantic correctness

  • is should only return Boolean.

    Methods starting with is, e.g. isActive should return true or false, nothing else, and should not produce side-effects.

  • set method shouldn't return anyhing.

    Setter methods imply that their result is a side-effect (of setting some variable) - returning something is confusing and counter-intuitive.

  • get should return something.

    By convention, getter methods should always return something. Example violation: method getImageData sets the state of some global variable and doesn't return anything.

  • Predicates should answer question.

    Method names in form of a predicate (e.g. isEnabled) should return a Boolean, not a null or an object. Example violation: attribute isReached of type int[] where the declared type and values are not documented.

  • Use Boolean variable names that imply true or false.

    If method or a variable is of Boolean type, its name should suggest so, e.g. isAuthorized().

  • Don't use get, is or has prefixes for functions with side-effects.

    Those words don't imply or suggest that side-effects can't happen, so the reader cannot assume that they will happen. If they do, it will probably be surprising to the reader.

  • Transform method should return anything.

    Example: apply_transformation_1(x) return return transformed x.

  • Method name and behavior should be consistent.

    For example, the result of calling function disable(...) should be a side-effect of disabling something, not, for example, returning object or function which can disable something.

  • Attribute name and type should be consistent.

    Example violation: attribute startObject is of type ObjectEnd.

  • Match plurality.

    If an attribute is of collection type, its name should reflect that, e.g. userNames: Set<String> instead of userName. Use plural nouns for function names which work on collections, e.g. convertDates(dates: List<Date>) instead of convertDate and return collections if name suggests so.

  • Don't contradict comments. Keep them up to date.

References/Further reading

  1. Arnaoudova, Venera, et al. “A new family of software anti-patterns: Linguistic anti-patterns.” 2013 17th European Conference on Software Maintenance and Reengineering. IEEE, 2013.
  2. Hilton, Peter, and Felienne Hermans. “Naming Guidelines for Professional Programmers.” PPIG. 2017
  3. https://github.com/Droogans/unmaintainable-code#naming
@FeryET
Copy link

FeryET commented Jul 31, 2023

Great article. Just found a typo and since this is about naming and spelling (I know I'm reaching), thought to point out.

Use stanard opposite pairs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment