naming
npx machina-cli add skill tslateman/duet/naming --openclawNaming as Design
Overview
Naming difficulty is a design smell. When you struggle to name something, the abstraction is wrong. Use naming as a lens to surface confused boundaries, mixed responsibilities, and domain misunderstanding.
Benner's Four Principles
Every name balances four properties. When they conflict, make the tradeoff deliberate.
- Understandability — Describe the context it represents. A reader should know what it does without reading the implementation
- Conciseness — Use only the words necessary. Longer is not clearer if the extra words add no meaning
- Consistency — Same word means the same thing everywhere. Different things get different names
- Distinguishability — A name must be distinct from its neighbors. Similar names for different things cause bugs
See references/principles.md for detailed rules and naming smells.
Two Modes
Review Mode
Examine names in recently changed code:
- Read the changed code
- For each name, ask:
- Does it pass all four principles?
- Could a reader understand this without context?
- Is the verb specific? ("process", "handle", "manage" almost never are)
- Does it match the domain language?
- Surface violations with specific alternatives
Design Mode
When naming is hard, use the struggle as a diagnostic:
- What does this thing actually do? List its responsibilities
- If the list has more than one item, the naming problem is a design problem — split it
- Who calls it? What do they expect?
- If it disappeared, what would break? That's what it is
- What would the domain expert call it?
Naming Smells
Names that signal design confusion:
| Smell | Example | What it reveals |
|---|---|---|
| Generic verb | handleData, processRequest | Unclear responsibility |
Suffix -Manager, -Helper, -Utils | UserManager, StringHelper | God object or junk drawer |
| And/Or in name | validateAndSave | Two responsibilities |
| Type in name | userList, nameString | Redundant or wrong abstraction level |
| Negated boolean | isNotReady, disableFeature | Double negatives in conditions |
| Abbreviated beyond recognition | usrSvcRsp | Conciseness without understandability |
Bloch's API Design Maxims
For public interfaces — APIs, library boundaries, module exports:
- Names should be self-documenting. If you need a comment to explain what a function does, rename it
- Same word, same meaning. Don't use "remove" in one place and "delete" in another for the same operation
- Principle of Least Astonishment. A method named
checkshould not modify state - If it's hard to name, the design is wrong. Rename the design, not just the symbol
Evans' Ubiquitous Language
Code names should match how domain experts talk:
- If the business says "order" and code says "purchase", one of them is wrong
- Naming mismatches between code and conversation reveal domain misunderstanding
- When renaming, update tests, docs, and conversations — not just code
Naming Checklist
For any name under review:
[ ] Specific verb (not handle/process/manage/do)
[ ] No unnecessary words
[ ] Consistent with similar names nearby
[ ] Distinguishable from neighbors
[ ] Matches domain language
[ ] Readable without implementation context
[ ] No embedded type information
[ ] Boolean reads as a question (isReady, hasPermission, canEdit)
Output Format
When reviewing names:
## Naming Review
### Must Rename
- `processData` → `validateInvoiceLineItems` — "process" hides
the actual responsibility; this only validates
- `handleClick` → `submitPayment` — name the action, not
the event
### Consider Renaming
- `userInfo` → `billingProfile` — more specific to its
actual contents
### Design Concern
- `OrderManager` has 12 methods spanning validation,
persistence, and notification. The naming struggle
reflects three responsibilities that should be separate
types.
Before/After Examples
Functions
| Before | After | Why |
|---|---|---|
processData(input) | validateInvoiceLineItems(invoice) | "Process" hides responsibility; name the action and the domain |
handleClick() | submitPayment() | Name the business action, not the DOM event |
doStuff(items) | deduplicateContacts(contacts) | Eliminate weasel verbs; name what it actually does |
run() | pollForStatusUpdates() | Ambiguous in any class with more than one operation |
Variables
| Before | After | Why |
|---|---|---|
data | unpaidInvoices | Generic noun → specific domain concept |
temp | unsavedDraft | Reveals intent; "temp" says nothing about lifecycle |
flag | requiresApproval | Reads as a question; boolean purpose is clear |
result | validationErrors | Names the content, not the role in the function |
list | activeSubscriptions | Type-in-name smell; name the contents instead |
Types and Modules
| Before | After | Why |
|---|---|---|
UserManager | UserRepository + UserNotifier | -Manager reveals multiple responsibilities; split them |
StringHelper | SlugFormatter | -Helper is a junk drawer; name the actual capability |
DataService | InventoryClient | Two generic words; name the domain and the role |
utils/misc.ts | pricing/discount-rules.ts | File path is a name too; make it navigable |
Booleans
| Before | After | Why |
|---|---|---|
isNotReady | isReady (invert usage) | Avoid double negatives in conditionals |
disableFeature | featureEnabled (invert usage) | Positive form reads naturally in if statements |
check | hasPermission | "Check" doesn't say what the answer means |
Strunk's Rule 12
"Use definite, specific, concrete language." The prose skill teaches this for English. Apply it identically to code:
| Vague | Specific |
|---|---|
getData | fetchUserProfile |
item | cartLineItem |
result | validationErrors |
info | shippingAddress |
temp | unsavedDraft |
See Also
/design— Hard-to-name things signal design problems/review— Code review surfaces naming issues; naming review deepens code review/prose— Strunk's rules apply to code names identically to English proseskills/FRAMEWORKS.md— Full framework index
Overview
Naming difficulty is a design smell. When naming is hard, boundaries become unclear and responsibilities blur, signaling domain misunderstandings. Naming as a design lens surfaces these issues using Benner's Four Principles to guide targeted renames that improve clarity and maintainability.
How This Skill Works
In Review Mode, scan recently changed code and evaluate each name against Understandability, Conciseness, Consistency, and Distinguishability, checking if a reader can grasp intent without implementation context, whether words are necessary, and if the naming matches domain language. In Design Mode, treat naming struggles as a diagnostic: list actual responsibilities, split if there are multiple, identify who calls it and what would fail if it disappeared, and align with domain expert terminology. This approach helps surface design problems rather than merely polishing labels.
When to Use It
- When asked to name or rename something (name this, rename, what should I call it)
- When a code review surfaces vague or misleading names
- When a symbol's name implies more than one responsibility (design smell)
- When you want to align names with domain language
- When you want to surface design problems through naming and boundaries
Quick Start
- Step 1: Read recently changed code and list names that fail Benner's Four Principles
- Step 2: For each offender, propose alternatives that reflect domain language and single responsibility
- Step 3: Implement targeted renames and update tests, docs, and conversations accordingly
Best Practices
- Use a specific verb (not handle/process/manage/do)
- Keep words concise and avoid unnecessary terms
- Maintain consistency with similar names nearby
- Ensure names are distinguishable from neighbors
- Match domain language and ensure readability without implementation context
Example Use Cases
- Before: handleData -> After: loadData (clarifies action and intent)
- Before: UserManager -> After: UserService (better boundary and responsibilities)
- Before: validateAndSave -> After: validateData and saveData (split responsibilities)
- Before: userList -> After: users (aligns with domain language and reduces type hinting)
- Before: isNotReady / disableFeature -> After: isReady / featureEnabled (remove negation and clarify state)