# Naming and Functions — Clean Code Chapters 2 and 3 Source: Robert C. Martin, *Clean Code*. Sample chapters online at the Pearson PDF; chapter summaries at Vivek Khatri's Ch. 2 notes and Herberto Graça's Ch. 3 summary. ## Contents - Meaningful names - N1. Intention-revealing - N2. No disinformation, no encodings - N3. Meaningful distinctions - N4. Searchable, pronounceable - N5. Class names are nouns, method names are verbs - N6. Banned generic names - Functions - F1. Small. Then smaller. - F2. Do one thing - F3. One level of abstraction per function - F4. Step-down rule - F5. Few arguments - F6. No flag arguments - F7. No output arguments / Command-Query Separation - F8. No side effects in queries - F9. Prefer exceptions to return codes - F10. Duplication is the root evil - Self-check for naming and functions ## Meaningful names ### N1. Intention-revealing A name should tell you *why it exists, what it does, and how it's used*. If you need a comment to explain a name, the name is wrong. **Bad:** ```text d // elapsed time in days ts = [] fn(xs) ``` **Good:** ```text elapsedDays timestamps filterOverdueInvoices(invoices) ``` ### N2. No disinformation, no encodings No Hungarian notation (`strName`, `iCount`). No interface-prefix `I` (`IUserService`). No member prefix `m_`. No "List" suffix unless the type is actually a list (`accountList` for a `set` is disinformation). **Bad:** `strFirstName`, `IUserRepo`, `m_count`, `userArray` (when it is not an array). **Good:** `first_name`, `UserRepo`, `count`, `users_by_id`. ### N3. Meaningful distinctions Do not differentiate names by adding noise words. `ProductInfo`, `ProductData`, `Product` — what's the difference? Same with `getActiveAccount` vs. `getActiveAccountInfo`. If the distinction is real, name the distinction. ### N4. Searchable, pronounceable Single-letter names are acceptable inside short loop scope (`for i in range(...)`). Anywhere else they hurt grep. `MAX_RETRIES` is searchable; `7` is not. If you can't read the name aloud in a code review, it's a bad name. `genymdhms` is a real-world example from the book — `generation_timestamp` is the fix. ### N5. Class names are nouns, method names are verbs `User`, `Invoice`, `Account` — classes are things. `saveInvoice`, `computeTotal`, `notifyUser` — methods are actions. A class named `ProcessInvoice` and a method named `Invoice` are both wrong. ### N6. Banned generic names Without a qualifier, these names always violate intention-revealing: - `data`, `data2`, `data_final` - `result`, `result_final` - `item`, `value`, `temp`, `obj`, `info` - `helper`, `manager`, `utils`, `common` - `handle_*`, `process_*`, `do_*` (when `*` is also generic) Qualified versions are fine: `raw_csv_bytes`, `parsed_invoice`, `dedup_by_email`. --- ## Functions ### F1. Small. Then smaller. Target ≤20 lines. Uncle Bob's harder pass says 2–4 lines is the goal. If a function does not fit on a screen, it does too much. Extract. ### F2. Do one thing A function does one thing when you cannot extract another function from it with a name that is not a restatement of its body. If `compute_invoice` contains a 10-line block that you could meaningfully call `apply_discount`, the original was doing more than one thing. ### F3. One level of abstraction per function Mixing levels is the most common subtle defect. Do not put an HTTP call, a SQL query, a regex parse, and a business rule in the same function — those are four levels. **Bad:** ```text renderUserReport(userId): connection = openDatabaseConnection() row = queryUserRow(connection, userId) displayName = row.firstName + " " + row.lastName markup = "

" + displayName + "

" return markup ``` Four levels: connection, query, formatting, presentation. **Good:** ```text renderUserReport(userId): user = userRepository.findById(userId) return userReportView.render(user) ``` ### F4. Step-down rule Read a file top-to-bottom; each function is followed by functions one level of abstraction below. Callers above callees. Confirmed by Uncle Bob himself on X. ### F5. Few arguments Zero is best. One is fine. Two is OK. Three "should be avoided." Four or more "requires very special justification" — usually means you should pass a config object. At five parameters, stop and extract a request/config object: record, struct, DTO, or equivalent. ### F6. No flag arguments A boolean parameter that switches behavior is always wrong. Split into two functions. **Bad:** ```text render(invoice, asHtml): if asHtml: ... else: ... ``` **Good:** ```text renderInvoiceHtml(invoice) renderInvoicePdf(invoice) ``` The same applies to `mode="x"` string enums when the mode changes behavior. If `mode` parameterizes data (locale, currency), it's fine. If it parameterizes *which function runs*, split. ### F7. No output arguments / Command-Query Separation A function either returns a value (query) or has a side effect (command). Never both. **Bad:** ```text save(record) -> boolean // Returns true if saved, false if record was not found. ``` What does the bool mean? Success? Found-ness? The caller can't tell. **Good:** ```text save(record) recordExists(recordId) -> boolean ``` ### F8. No side effects in queries A getter-style, finder-style, or predicate-style function must not mutate state. If it caches, log the cache write at debug level; do not change observable behavior. ### F9. Prefer exceptions to return codes `if save(x):` is a code smell. Either save succeeds (returns nothing) or it raises (`InvoiceSaveError`). Return codes proliferate up the call stack and get forgotten; exceptions can't be ignored silently. ### F10. Duplication is the root evil If two functions share a non-trivial block, extract it. But — see [dry-kiss-yagni.md](dry-kiss-yagni.md) for when this is wrong (Sandi Metz's "wrong abstraction" caveat). --- ## Self-check for naming and functions Before you ship code: 1. Do all names answer "what does this represent" without a comment? 2. Are functions ≤20 lines? 3. Are functions doing one thing? (Can you extract another function with a non-restating name? If yes, you're doing more than one.) 4. Are mixed abstraction levels eliminated? 5. Are there any functions with >4 parameters? Extract a config object. 6. Are there boolean flag arguments? Split. 7. Do any functions both return a value *and* mutate state in a way callers depend on? Split.