| name | naming-things |
|---|---|
| description | Naming conventions for classes, functions, variables, unit tests, time, abbreviations, metrics/units, synonyms, negations, and versioning. Use whenever writing, reviewing, or refactoring code to keep names clear, consistent, and self-documenting. |
A humble effort to solve computer science's second-hardest problem.
This repository is packaged as a Claude Code plugin, exposing a naming-things skill that loads these guidelines automatically whenever you write or review code in Claude Code. Install it from the plugin marketplace (the marketplace entry points to this repo).
Tip
Alternative usage (no plugin):
Simply copy the following snippet into your AGENTS.md or CONTRIBUTING.md file.
When writing code, you MUST ALWAYS follow the [naming-things](https://raw.githubusercontent.com/codingjoe/naming-things/refs/heads/main/README.md) guidelines.
<!--
Bots/Agents MUST use:
curl -sSL https://raw.githubusercontent.com/codingjoe/naming-things/refs/heads/main/README.md | head -n 500
-->- Classes and Functions
- Unit Tests
- Time
- Abbreviations
- Metrics, Measurements, and Units
- Utils & Helpers
- Synonyms
- Avoid Negations
- Versioning
There are only two hard things in Computer Science: cache invalidation and naming things.
— Phil Karlton
This document concerns natural language conventions, not syntax or code style. Rules are language-agnostic, but examples are given in Python.
Class names are nouns or noun phrases. Think German compound nouns. E.g., UserProfile, OrderItem, PaymentProcessor.
Class names are singular because while its instances may represent multiple entities (e.g., a User class representing multiple user instances), the class itself is a blueprint for a single entity.
Specialize, don't generalize. If you feel the urge to name a base class BaseSomething or AbstractSomething, go the other way.
Make children more specific, not parents more general.
class Vehicle:
"""A means of transporting people or goods."""
class Car(Vehicle):
"""A road vehicle, typically with four wheels, powered by an internal combustion engine or electric motor."""
class SUV(Car):
"""A pedestrian death machine."""class BaseCar:
"""A road vehicle, typically with four wheels, powered by an internal combustion engine or electric motor."""
class SportsCar(BaseCar):
"""Only fun in Germany."""Function represents an action a caller can perform. Use verbs or verb phrases. E.g., send(), calculate_total().
Function names must clearly communicate their external behavior, including side effects. E.g., fetch_or_404() makes it explicit that it may raise a 404 error.
They must not expose internal implementation details. E.g., avoid send_via_smtp(); use send() instead.
Loose functions should be the exception, not the rule. Prefer class methods or instance methods to group related functionality. If a function includes a noun in its name, it probably belongs to that noun's class. E.g., instead of fetch_user_profile(user_id), implement UserProfile.fetch(user_id).
Avoid including object names, as the method is probably attached to the wrong class. E.g., instead of user.send_email(), use UserEmail(user).send().
Avoid assigning variables that are only used once. If a value is asserted immediately or returned in the next line without further access, use it inline.
Unit tests should match their API counterparts to be easily navigable and discoverable. A simple text search for a function or class must reveal both its implementation and tests quickly.
Test names use double underscores to separate the function or class name from the scenario (e.g., test_get_user__ok, test_get_user__raise_value_error). Test classes are prefixed with Test in Python or wrapped in describe blocks in JavaScript. Test descriptions must use imperative mood and avoid redundant words like "should", "expect", or "it". Assertion messages must add meaningful context beyond the assertion itself or be omitted. In Node.js, use strict assertions by default with import assert from "node:assert/strict" for shorter function names and stricter equality checks.
def get_user(user_id):
"""Fetch user from database."""
...
class TestGetUser: # prefix with Test
def test_get_user__ok(self): # double underscore separates scenario
"""Return user when found.""" # imperative mood
assert isinstance(get_user(1), User) # inline single-use values
def test_get_user__raise_value_error(self): # descriptive scenario name
"""Raise ValueError when user ID is invalid.""" # meaningful context
with pytest.raises(ValueError):
get_user(-1)import assert from "node:assert/strict"; // strict assertions by default
function getUser(userId) {
// Fetch user from database
}
describe("getUser", () => { // wrap in describe block
test("ok", () => { // no "should", "expect", or "it"
assert(getUser(1) instanceof User); // inline single-use values
});
test("raise ValueError", () => { // descriptive scenario
assert.throws(() => getUser(-1), ValueError);
});
});
// assertion messages add context or are omitted
assert.ok(user.age >= 18, "User must be adult to access premium features");
assert.equal(user.name, "Alice"); // omit when self-explanatorydef test_validate_email(self):
"""It should return True when email is valid.""" # avoid "should", "it"
def test_validate_email(self):
"""We expect True for valid emails.""" # avoid "expect"
def test_create_user__ok(self):
"""Return user instance."""
user = create_user("Alice") # unnecessary variable
assert isinstance(user, User)test("validateEmail", () => {
// It should return true when email is valid // avoid "it", "should"
});
test("createUser__ok", () => {
const user = createUser("Alice"); // unnecessary variable
assert(user instanceof User);
});
assert.equal(user.name, "Alice", "user.name should equal Alice"); // repeats assertionTime zones are hard; don't make it harder.
Points in time should always have a little at-suffix to communicate they represent a specific moment rather than a duration or interval.
Furthermore, they must be in the language's date type (e.g., datetime in Python, Date in JavaScript) as well as timezone-aware.
Hindsight is 20/20; name all dates in the past tense, e.g., created_at, updated_at, deleted_at. Even if the event is in the future, e.g., scheduled_at, expired_at, started_at. Time passes. By the time you are debugging code, everything is in the past.
Avoid locale-specific string representations or include a timezone suffix. Suffix dates according to their IANA timezone.
import datetime
# base case
created_at: datetime.datetime = datetime.datetime.now(tz=datetime.timezone.utc)
# local date with timezone
created_at_europe_berlin: datetime.date = datetime.date.today()
created_at_utc: datetime.date = datetime.date.today()
# UNIX Epoch timestamp
created_at_ts: float = datetime.datetime.now(tz=datetime.timezone.utc).timestamp()
# ISO 8601 string with timezone
created_at_iso: str = datetime.datetime.now(tz=datetime.timezone.utc).isoformat()import datetime
# present tense
start = datetime.datetime.now(tz=datetime.timezone.utc)
# no event suffix
created = datetime.datetime.now()
# naive datetime
created_at: datetime.datetime = datetime.datetime.now()Durations should be either unambiguously typed (e.g., timedelta in Python, Duration in Java) or have a suffix indicating the unit of time (e.g., secs, ms, mins, hours, days).
import datetime
# typed duration
timeout: datetime.timedelta = datetime.timedelta(seconds=30)
# unit suffix
timeout_secs: int = 30
timeout_ms: int = 30000# no interval specific type or unit
timeout: int = 30Abbreviations rely on context you may or may not have.
Don't use abbreviations!
Unless… they are technical acronyms that are universally known outside your team's domain, e.g., HTML, URL. Use them if they are more common than their unabbreviated counterparts.
- HTML (HyperText Markup Language)
- URL (Uniform Resource Locator)
- URI (Uniform Resource Identifier)
- CPU (Central Processing Unit)
- GPU (Graphics Processing Unit)
- RAM (Random Access Memory)
- JSON (JavaScript Object Notation)
- XML (eXtensible Markup Language)
- HTTP (HyperText Transfer Protocol)
- HTTPS (HyperText Transfer Protocol Secure)
- FTP (File Transfer Protocol)
- SMTP (Simple Mail Transfer Protocol)
- DNS (Domain Name System)
- TLS (Transport Layer Security)
- SSL (Secure Sockets Layer)
- TCP (Transmission Control Protocol)
- UDP (User Datagram Protocol)
- SQL (Structured Query Language)
- API (Application Programming Interface)
- GUI (Graphical User Interface)
- IDE (Integrated Development Environment)
- OS (Operating System)
- IPv4 (Internet Protocol Version 4)
- IPv6 (Internet Protocol Version 6)
- IP – could mean
Intellectual Property, useIPv4orIPv6 - temp – use
temporaryortemperature - addr – use
address - num – use
number - cnt – use
count - cfg – use
configorconfiguration - msg – use
message - calc – use
calculateorcalculation - init – use
initializeorinitialization - var – use
variable - obj – use
object - func – use
functionormethod - btn – use
button - usr – use
user - pwd – use
password - db – use
database
Add an explicit unit suffix to all measurements. Use SI unit symbols for brevity.
When persisting metrics, consider using SI (metric) units instead of freedom units, as they are the international standard and simplify conversions.
class WeatherReport:
temperature_c: float # temperature in degrees Celsius
distance_km: float # distance in kilometers
weight_kg: float # weight in kilograms
speed_kmh: float # speed in kilometers per hour
volume_l: float # volume in litersclass WeatherReport:
temperature: float # ambiguous
distance: float # ambiguous
weight: float # ambiguous
speed: float # ambiguous
volume: float # ambiguousAlways be explicit about sizes. Size matters! Do you know the size of a BIGINT or a SMALLINT in your database of choice?
from PIL import Image
class Profile:
picture_w1200: Image # if width is 1200 pixels and height is variable
picture_w400_h300: Image # if width is 400 pixels and height is 300 pixelsfrom PIL import Image
class Profile:
picture_small: Image # ambiguous
picture_large: Image # ambiguous
picture_thumbnail: Image # ambiguousA German term for a place where leftover goods are collected and sold cheaply.
Avoid generic names like utils, helpers, common, shared, lib, core, base, foundation, services, components, etc.
For type-agnostic functions, use inheritance and class methods to group them meaningfully.
E.g., instead of a utils module with a function to_json(obj), create a Object.to_json(self) method on relevant classes.
If there isn't a type yet, create one. E.g., instead of a helpers module with a function send_email(to, subject, body), create an EmailClient class with a send_email(self, to, subject, body) method.
Avoid synonyms to reduce cognitive load. Pick one term and stick with it throughout your codebase.
Here's a non-exhaustive list of common synonyms and their preferred alternatives:
| Avoid | Prefer |
|---|---|
| fetch/retrieve | fetch |
| search/query/find | search |
| get/load/access | get |
| send/dispatch/transmit | send |
| create/make/build | create |
| delete/remove/destroy | delete |
| update/modify/change | update |
| calculate/compute/determine | calculate |
| item/thing/object | item |
| data/info/information | data |
| value/val/amount | value |
| list/array/collection | list |
| clean/sanitize/normalize | clean |
| start/begin/initiate | start |
| stop/end/terminate | stop |
| many/multiple/numerous/several | multiple |
Be specific and avoid vague terms. E.g., instead of number, use count, index, mean, etc.
Here's a non-exhaustive list of ambiguous terms and their preferred alternatives:
| Avoid | Prefer |
|---|---|
| number | count/index/mean |
| average | mean/median |
| amount | sum/count/min/max |
Some terms have contextual meanings and should be used explicitly in those contexts.
- Get: Use for simple, synchronous access to data already in memory or readily available.
- Fetch: Use for asynchronous or remote data retrieval, such as from a database or API.
- Search: Use when querying data based on specific criteria or filters with an unknown result set including zero results.
- Set: Use for assigning values to variables, properties, or configurations.
- Send: Use for transmitting data or messages over a network or between components. If HTTP is involved, always use the correct request method (e.g.,
post(),put()).
Use positive language to avoid double negations and improve readability.
E.g., if (is_enabled) is clearer than if (!is_disabled).
enable_feature = False # not: disable_feature = True
is_valid = True # not: is_invalid = False
has_permission = True # not: lacks_permission = Falsedisable_feature = True # confusing when set to False
is_not_active = False # double negation
if not is_disabled: # hard to parse| Avoid | Prefer |
|---|---|
| disable | enable |
| invalid | valid |
| incomplete | complete |
| does_not_exist | exists |
| prevent | grant |
| ignore | handle |
| avoid | allow |
| fail | succeed |
| missing | present |
| incorrect | correct |
| unavailable | available |
| inactive | active |
| prohibited | permitted |
| rejected | accepted |
| denied | granted |
Note
Use negative terms when they're the standard (e.g., disabled for HTMLInputElements) or inherently negative (e.g., error, exception).
It's simple: if your project does continuous releases, use Semantic Versioning.
If you are on a fixed release cycle, use calver YYYY.MINOR.MICRO
. E.g., 2024.2.3 for the third patch of the second minor release in 2024.
Here's a diagram to help you decide:
flowchart TD
A(Start) --> B{releases}
B -- continuous --> D[semver]
B -- fixed cycle --> C[calver]
Do not invent your own versioning scheme.
- Naming Things in Code by CodeAesthetic
This work is licensed under a CC0 1.0 Universal License. Do with it as you please; maybe leave a star on GitHub. Thanks <3

