{"id":44031944,"url":"https://github.com/codingjoe/naming-things","last_synced_at":"2026-02-07T19:14:05.760Z","repository":{"id":325064147,"uuid":"1099681136","full_name":"codingjoe/naming-things","owner":"codingjoe","description":"Solving computer science's second-hardest problem","archived":false,"fork":false,"pushed_at":"2026-02-01T20:37:15.000Z","size":70,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-01T21:51:44.203Z","etag":null,"topics":["conventions"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/codingjoe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"codingjoe","buy_me_a_coffee":"codingjoe","custom":"https://www.paypal.me/codingjoe"}},"created_at":"2025-11-19T10:01:14.000Z","updated_at":"2026-02-01T20:37:17.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/codingjoe/naming-things","commit_stats":null,"previous_names":["codingjoe/naming-things"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/codingjoe/naming-things","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codingjoe%2Fnaming-things","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codingjoe%2Fnaming-things/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codingjoe%2Fnaming-things/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codingjoe%2Fnaming-things/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/codingjoe","download_url":"https://codeload.github.com/codingjoe/naming-things/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codingjoe%2Fnaming-things/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29205241,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-07T17:44:10.191Z","status":"ssl_error","status_checked_at":"2026-02-07T17:44:07.936Z","response_time":63,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["conventions"],"created_at":"2026-02-07T19:14:05.148Z","updated_at":"2026-02-07T19:14:05.747Z","avatar_url":"https://github.com/codingjoe.png","language":null,"funding_links":["https://github.com/sponsors/codingjoe","https://buymeacoffee.com/codingjoe","https://www.paypal.me/codingjoe"],"categories":[],"sub_categories":[],"readme":"# _Naming Things_\n\n**A humble effort to solve computer science's second-hardest problem.**\n\n\u003e [!TIP]\n\u003e **Usage:**\n\u003e Simply copy the following snippet into your `AGENTS.md` or `CONTRIBUTING.md` file.\n\u003e\n\u003e ```markdown\n\u003e When writing code, you MUST ALWAYS follow the [naming-things](https://raw.githubusercontent.com/codingjoe/naming-things/refs/heads/main/README.md) guidelines.\n\u003e \u003c!--\n\u003e Bots/Agents MUST use:\n\u003e curl -sSL https://raw.githubusercontent.com/codingjoe/naming-things/refs/heads/main/README.md | head -n 500\n\u003e --\u003e\n\u003e ```\n\n\u003c!-- mdformat-toc start --slug=github --no-anchors --maxlevel=2 --minlevel=2 --\u003e\n\n- [Classes and Functions](#classes-and-functions)\n- [Unit Tests](#unit-tests)\n- [Time](#time)\n- [Abbreviations](#abbreviations)\n- [Metrics, Measurements, and Units](#metrics-measurements-and-units)\n- [Utils \u0026 Helpers](#utils--helpers)\n- [Synonyms](#synonyms)\n- [Avoid Negations](#avoid-negations)\n- [Versioning](#versioning)\n\n\u003c!-- mdformat-toc end --\u003e\n\n# Preamble\n\n\u003e There are only two hard things in Computer Science: cache invalidation and naming things.\n\u003e\n\u003e — Phil Karlton\n\nThis document concerns natural language conventions, not syntax or code style. Rules are language-agnostic, but examples are given in Python.\n\n[![Permanence\n](https://imgs.xkcd.com/comics/permanence.png)](https://xkcd.com/910/)\n\n## Classes and Functions\n\n### Classes\n\nClass names are nouns or noun phrases. Think German compound nouns. E.g., `UserProfile`, `OrderItem`, `PaymentProcessor`.\n\nClass 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.\n\n#### Inheritance\n\nSpecialize, don't generalize. If you feel the urge to name a base class `BaseSomething` or `AbstractSomething`, go the other way.\nMake children more specific, not parents more general.\n\n##### Do's\n\n```python\nclass Vehicle:\n    \"\"\"A means of transporting people or goods.\"\"\"\n\n\nclass Car(Vehicle):\n    \"\"\"A road vehicle, typically with four wheels, powered by an internal combustion engine or electric motor.\"\"\"\n\n\nclass SUV(Car):\n    \"\"\"A pedestrian death machine.\"\"\"\n```\n\n##### Don'ts\n\n```python\nclass BaseCar:\n    \"\"\"A road vehicle, typically with four wheels, powered by an internal combustion engine or electric motor.\"\"\"\n\n\nclass SportsCar(BaseCar):\n    \"\"\"Only fun in Germany.\"\"\"\n```\n\n### Functions\n\nFunction represents an action a caller can perform. Use verbs or verb phrases. E.g., `send()`, `calculate_total()`.\n\nFunction 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.\nThey must not expose internal implementation details. E.g., avoid `send_via_smtp()`; use `send()` instead.\n\nLoose 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)`.\n\n### Methods\n\nAvoid including object names, as the method is probably attached to the wrong class. E.g., instead of `user.send_email()`, use `UserEmail(user).send()`.\n\n### Variables\n\nAvoid 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.\n\n## Unit Tests\n\nUnit 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.\n\nTest 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.\n\n### Do's\n\n```python\ndef get_user(user_id):\n    \"\"\"Fetch user from database.\"\"\"\n    ...\n\n\nclass TestGetUser:  # prefix with Test\n    def test_get_user__ok(self):  # double underscore separates scenario\n        \"\"\"Return user when found.\"\"\"  # imperative mood\n        assert isinstance(get_user(1), User)  # inline single-use values\n\n    def test_get_user__raise_value_error(self):  # descriptive scenario name\n        \"\"\"Raise ValueError when user ID is invalid.\"\"\"  # meaningful context\n        with pytest.raises(ValueError):\n            get_user(-1)\n```\n\n```javascript\nimport assert from \"node:assert/strict\"; // strict assertions by default\n\nfunction getUser(userId) {\n    // Fetch user from database\n}\n\ndescribe(\"getUser\", () =\u003e { // wrap in describe block\n    test(\"ok\", () =\u003e { // no \"should\", \"expect\", or \"it\"\n        assert(getUser(1) instanceof User); // inline single-use values\n    });\n\n    test(\"raise ValueError\", () =\u003e { // descriptive scenario\n        assert.throws(() =\u003e getUser(-1), ValueError);\n    });\n});\n\n// assertion messages add context or are omitted\nassert.ok(user.age \u003e= 18, \"User must be adult to access premium features\");\nassert.equal(user.name, \"Alice\"); // omit when self-explanatory\n```\n\n### Don'ts\n\n```python\ndef test_validate_email(self):\n    \"\"\"It should return True when email is valid.\"\"\"  # avoid \"should\", \"it\"\n\n\ndef test_validate_email(self):\n    \"\"\"We expect True for valid emails.\"\"\"  # avoid \"expect\"\n\n\ndef test_create_user__ok(self):\n    \"\"\"Return user instance.\"\"\"\n    user = create_user(\"Alice\")  # unnecessary variable\n    assert isinstance(user, User)\n```\n\n```javascript\ntest(\"validateEmail\", () =\u003e {\n    // It should return true when email is valid  // avoid \"it\", \"should\"\n});\n\ntest(\"createUser__ok\", () =\u003e {\n    const user = createUser(\"Alice\"); // unnecessary variable\n    assert(user instanceof User);\n});\n\nassert.equal(user.name, \"Alice\", \"user.name should equal Alice\"); // repeats assertion\n```\n\n## Time\n\n_[Time zones are hard](https://www.youtube.com/watch?v=-5wpm-gesOY); don't make it harder._\n\n### Events \u0026 Points in Time\n\nPoints in time should always have a little `at`-suffix to communicate they represent a specific moment rather than a duration or interval.\n\nFurthermore, they must be in the language's date type (e.g., `datetime` in Python, `Date` in JavaScript) as well as timezone-aware.\n\nHindsight 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.\n\nAvoid locale-specific string representations or include a timezone suffix. Suffix dates according to their [IANA timezone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).\n\n#### Do's\n\n```python\nimport datetime\n\n# base case\ncreated_at: datetime.datetime = datetime.datetime.now(tz=datetime.timezone.utc)\n\n# local date with timezone\ncreated_at_europe_berlin: datetime.date = datetime.date.today()\ncreated_at_utc: datetime.date = datetime.date.today()\n\n# UNIX Epoch timestamp\ncreated_at_ts: float = datetime.datetime.now(tz=datetime.timezone.utc).timestamp()\n# ISO 8601 string with timezone\ncreated_at_iso: str = datetime.datetime.now(tz=datetime.timezone.utc).isoformat()\n```\n\n#### Don'ts\n\n```python\nimport datetime\n\n# present tense\nstart = datetime.datetime.now(tz=datetime.timezone.utc)\n\n# no event suffix\ncreated = datetime.datetime.now()\n\n# naive datetime\ncreated_at: datetime.datetime = datetime.datetime.now()\n```\n\n### Durations and intervals\n\nDurations 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`).\n\n#### Do's\n\n```python\nimport datetime\n\n# typed duration\ntimeout: datetime.timedelta = datetime.timedelta(seconds=30)\n# unit suffix\ntimeout_secs: int = 30\ntimeout_ms: int = 30000\n```\n\n#### Don'ts\n\n```python\n# no interval specific type or unit\ntimeout: int = 30\n```\n\n## Abbreviations\n\n\u003e Abbreviations rely on context you may or may not have.\n\u003e\n\u003e — [CodeAesthetic](https://www.youtube.com/watch?v=-J3wNP6u5YU)\n\n[![Nomenclature](https://imgs.xkcd.com/comics/nomenclature.png)](https://xkcd.com/1221/)\n\n**Don't use abbreviations!**\n\nUnless… 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.\n\n### Do's\n\n- **HTML** (HyperText Markup Language)\n- **URL** (Uniform Resource Locator)\n- **URI** (Uniform Resource Identifier)\n- **CPU** (Central Processing Unit)\n- **GPU** (Graphics Processing Unit)\n- **RAM** (Random Access Memory)\n- **JSON** (JavaScript Object Notation)\n- **XML** (eXtensible Markup Language)\n- **HTTP** (HyperText Transfer Protocol)\n- **HTTPS** (HyperText Transfer Protocol Secure)\n- **FTP** (File Transfer Protocol)\n- **SMTP** (Simple Mail Transfer Protocol)\n- **DNS** (Domain Name System)\n- **TLS** (Transport Layer Security)\n- **SSL** (Secure Sockets Layer)\n- **TCP** (Transmission Control Protocol)\n- **UDP** (User Datagram Protocol)\n- **SQL** (Structured Query Language)\n- **API** (Application Programming Interface)\n- **GUI** (Graphical User Interface)\n- **IDE** (Integrated Development Environment)\n- **OS** (Operating System)\n- **IPv4** (Internet Protocol Version 4)\n- **IPv6** (Internet Protocol Version 6)\n\n### Don'ts\n\n- IP – could mean `Intellectual Property`, use `IPv4` or `IPv6`\n- temp – use `temporary` or `temperature`\n- addr – use `address`\n- num – use `number`\n- cnt – use `count`\n- cfg – use `config` or `configuration`\n- msg – use `message`\n- calc – use `calculate` or `calculation`\n- init – use `initialize` or `initialization`\n- var – use `variable`\n- obj – use `object`\n- func – use `function` or `method`\n- btn – use `button`\n- usr – use `user`\n- pwd – use `password`\n- db – use `database`\n\n## Metrics, Measurements, and Units\n\n### Units\n\nAdd an explicit unit suffix to all measurements. Use [SI unit symbols](https://en.wikipedia.org/wiki/International_System_of_Units#Unit_symbols) for brevity.\n\nWhen persisting metrics, consider using SI (metric) units instead of [freedom units](https://en.wiktionary.org/wiki/freedom_units), as they are the international standard and simplify conversions.\n\n#### Do's\n\n```python\nclass WeatherReport:\n    temperature_c: float  # temperature in degrees Celsius\n    distance_km: float  # distance in kilometers\n    weight_kg: float  # weight in kilograms\n    speed_kmh: float  # speed in kilometers per hour\n    volume_l: float  # volume in liters\n```\n\n#### Don'ts\n\n```python\nclass WeatherReport:\n    temperature: float  # ambiguous\n    distance: float  # ambiguous\n    weight: float  # ambiguous\n    speed: float  # ambiguous\n    volume: float  # ambiguous\n```\n\n### Sizes\n\nAlways be explicit about sizes. Size matters! Do you know the size of a BIGINT or a SMALLINT in your database of choice?\n\n#### Do's\n\n```python\nfrom PIL import Image\n\n\nclass Profile:\n    picture_w1200: Image  # if width is 1200 pixels and height is variable\n    picture_w400_h300: Image  # if width is 400 pixels and height is 300 pixels\n```\n\n#### Don'ts\n\n```python\nfrom PIL import Image\n\n\nclass Profile:\n    picture_small: Image  # ambiguous\n    picture_large: Image  # ambiguous\n    picture_thumbnail: Image  # ambiguous\n```\n\n## Utils \u0026 Helpers\n\n\u003e **[Resterampe /ˈʁɛstɐˌʁampə/](https://en.wiktionary.org/wiki/Resterampe)**\n\u003e\n\u003e A German term for a place where leftover goods are collected and sold cheaply.\n\nAvoid generic names like `utils`, `helpers`, `common`, `shared`, `lib`, `core`, `base`, `foundation`, `services`, `components`, etc.\n\nFor type-agnostic functions, use inheritance and class methods to group them meaningfully.\nE.g., instead of a `utils` module with a function `to_json(obj)`, create a `Object.to_json(self)` method on relevant classes.\n\nIf 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.\n\n## Synonyms\n\nAvoid synonyms to reduce cognitive load. Pick one term and stick with it throughout your codebase.\n\nHere's a non-exhaustive list of common synonyms and their preferred alternatives:\n\n| Avoid                          | Prefer    |\n| ------------------------------ | --------- |\n| fetch/retrieve                 | fetch     |\n| search/query/find              | search    |\n| get/load/access                | get       |\n| send/dispatch/transmit         | send      |\n| create/make/build              | create    |\n| delete/remove/destroy          | delete    |\n| update/modify/change           | update    |\n| calculate/compute/determine    | calculate |\n| item/thing/object              | item      |\n| data/info/information          | data      |\n| value/val/amount               | value     |\n| list/array/collection          | list      |\n| clean/sanitize/normalize       | clean     |\n| start/begin/initiate           | start     |\n| stop/end/terminate             | stop      |\n| many/multiple/numerous/several | multiple  |\n\nBe specific and avoid vague terms. E.g., instead of `number`, use `count`, `index`, `mean`, etc.\n\nHere's a non-exhaustive list of ambiguous terms and their preferred alternatives:\n\n| Avoid   | Prefer            |\n| ------- | ----------------- |\n| number  | count/index/mean  |\n| average | mean/median       |\n| amount  | sum/count/min/max |\n\n### Exceptions\n\nSome terms have contextual meanings and should be used explicitly in those contexts.\n\n#### Get vs. Fetch vs. Search\n\n- **Get**: Use for simple, synchronous access to data already in memory or readily available.\n- **Fetch**: Use for asynchronous or remote data retrieval, such as from a database or API.\n- **Search**: Use when querying data based on specific criteria or filters with an unknown result set including zero results.\n\n#### Set vs. Send\n\n- **Set**: Use for assigning values to variables, properties, or configurations.\n- **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()`).\n\n## Avoid Negations\n\nUse positive language to avoid double negations and improve readability.\nE.g., `if (is_enabled)` is clearer than `if (!is_disabled)`.\n\n### Do's\n\n```python\nenable_feature = False  # not: disable_feature = True\nis_valid = True  # not: is_invalid = False\nhas_permission = True  # not: lacks_permission = False\n```\n\n### Don'ts\n\n```python\ndisable_feature = True  # confusing when set to False\nis_not_active = False  # double negation\nif not is_disabled:  # hard to parse\n```\n\n### Common Patterns\n\n| Avoid          | Prefer    |\n| -------------- | --------- |\n| disable        | enable    |\n| invalid        | valid     |\n| incomplete     | complete  |\n| does_not_exist | exists    |\n| prevent        | grant     |\n| ignore         | handle    |\n| avoid          | allow     |\n| fail           | succeed   |\n| missing        | present   |\n| incorrect      | correct   |\n| unavailable    | available |\n| inactive       | active    |\n| prohibited     | permitted |\n| rejected       | accepted  |\n| denied         | granted   |\n\n\u003e [!NOTE]\n\u003e Use negative terms when they're the standard (e.g., `disabled` for HTMLInputElements) or inherently negative (e.g., `error`, `exception`).\n\n## Versioning\n\nIt's simple: if your project does continuous releases, use [Semantic Versioning](https://semver.org/).\nIf you are on a fixed release cycle, use [calver](https://calver.org/) `YYYY.MINOR.MICRO`\n. E.g., `2024.2.3` for the third patch of the second minor release in 2024.\n\nHere's a diagram to help you decide:\n\n```mermaid\nflowchart TD\n    A(Start) --\u003e B{releases}\n    B -- continuous --\u003e D[semver]\n    B -- fixed cycle --\u003e C[calver]\n```\n\nDo not invent your own versioning scheme.\n\n# Honorable mentions\n\n- [Naming Things in Code](https://www.youtube.com/watch?v=-J3wNP6u5YU) by CodeAesthetic\n\n# License\n\nThis work is licensed under a [CC0 1.0 Universal License](https://creativecommons.org/publicdomain/zero/1.0/).\nDo with it as you please; maybe leave a star on [GitHub](https://github.com/codingjoe/naming-things). Thanks \\\u003c3\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodingjoe%2Fnaming-things","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcodingjoe%2Fnaming-things","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodingjoe%2Fnaming-things/lists"}