Chapter 3 Flashcards — Functions

flashcards clean-code functions

What is the single most important rule about functions from Clean Code?
?
“FUNCTIONS SHOULD DO ONE THING. THEY SHOULD DO IT WELL. THEY SHOULD DO IT ONLY.” A function does one thing if you cannot extract another function from it with a name that is not merely a restatement of the implementation.

How can you test whether a function does more than one thing?
?
Try to extract another function from it. If you can create a new function with a meaningful name (not just a restatement of what the code already says), the original function is doing more than one thing.

What is the recommended maximum length for a function?
?
Martin recommends functions be 20 lines or fewer, with each block (if/else/while bodies) being only 1–2 lines long — ideally a function call with a descriptive name. The smaller the function, the easier it is to name, test, and reason about.

What is the “step-down rule” for function abstraction?
?
Reading code top to bottom, each function should introduce the next level of abstraction. You should be able to read the source file like a narrative: “To do X, we do A, then B, then C. To do A, we do…” This is the step-down rule.

What is wrong with mixing getHtml() and .append("\n") in the same function?
?
They operate at different levels of abstractiongetHtml() is high-level (page rendering), while .append("\n") is low-level (string concatenation). Mixing levels confuses readers about which details are important and which are incidental.

Why do switch statements violate good design principles?
?
A switch on a type (employee type, order status) tends to be duplicated everywhere that cares about the type — calculatePay(), isFullTime(), deliverPay(). This violates the Single Responsibility Principle (SRP) and the Open-Closed Principle (OCP): adding a new type forces you to find and change every switch.

How do you fix a duplicated switch statement?
?
Bury it in an Abstract Factory that creates a polymorphic object. The switch appears exactly once at construction time. After that, all callers use the polymorphic interface (e.g., employee.calculatePay()) and never switch on type again.

What are the four argument count categories and their verdicts?
?
Niladic (0 args) — best; Monadic (1 arg) — good; Dyadic (2 args) — acceptable; Triadic (3 args) — avoid; Polyadic (4+ args) — refactor immediately using an argument object.

What is an “argument object” and when should you use it?
?
An argument object is a class or record that groups 2–3 conceptually related arguments into a single parameter. Use it when arguments form a cohesive concept (e.g., Point center instead of double x, double y). This reduces arity and clarifies intent at the call site.

Why are flag arguments (boolean parameters) a code smell?
?
Passing a boolean into a function loudly proclaims the function does two things: one thing when true, another when false. This violates Do One Thing. render(true) is meaningless at the call site. The fix: split into renderForSuite() and renderForSingleTest().

What is a “side effect” in the context of functions?
?
A side effect is a hidden action that a function performs beyond what its name implies. Example: checkPassword() that also initializes a session. Callers who only want to verify a password unknowingly create sessions, causing temporal coupling and subtle bugs.

What is the Command Query Separation (CQS) principle?
?
A function should either do something (command: mutate state, write to disk, send email) or answer something (query: return a value, check a condition) — never both. Mixing the two leads to confusing code like if (set("username", "unclebob")) where the caller cannot tell if set is setting or checking.

Why should functions prefer throwing exceptions over returning error codes?
?
Error codes require the caller to handle the error immediately, leading to nested conditionals that bury the happy path. Exceptions allow the normal path to remain clean — the caller can catch errors in a separate catch block far removed from the logic that triggered them.

What is the “Extract Try/Catch Bodies” rule?
?
The bodies inside try and catch blocks should be extracted into their own named functions. A try/catch mixes two jobs — the happy-path logic and the error-recovery logic — in one function. After extraction: try { performDeletion(id); } catch (DBException e) { handleDeletionFailure(e, id); }.

Why is DRY (Don’t Repeat Yourself) especially important for functions?
?
Every duplicated function body is a future bug waiting to happen. When the algorithm changes, you must find and update every copy. Miss one and you introduce a subtle inconsistency. DRY means extracting the shared logic into a single, named function called from every site.

What is Dijkstra’s structured programming rule for functions?
?
Dijkstra required that every function and every block within a function have one entry and one exit: a single return statement, no break or continue in loops, and never goto. For small functions this matters less — early returns (guard clauses) actively improve readability.

When is an early return (guard clause) preferable to a single-return structure?
?
In small functions (under 10 lines), early returns eliminate nesting and make precondition checks readable. The single-return rule is most valuable in long, complex functions where tracking all the exit paths is hard. The answer to those functions is to break them up, not enforce a single return.

What does render(true) at a call site tell you?
?
Nothing useful. The boolean argument destroys readability. The reader must look up the function signature to understand what true means. The fix: replace with two explicit functions — renderForSuite() and renderForSingleTest() — that are self-documenting at every call site.

What is the difference between checkPassword(username, password) that initializes a session vs. one that does not?
?
The one that initializes a session has a hidden side effect. Callers who only want to verify credentials unexpectedly mutate session state. The function name is a lie. Either rename it to checkPasswordAndInitializeSession() to make the effect explicit, or better, separate the two concerns.

What happens when you have a switch statement in calculatePay(), isFullTime(), and deliverPay()?
?
You’ve created duplicated type dispatch — every method that cares about employee type has its own copy of the switch. Adding a new employee type requires finding and updating all three (and every future method). This is the OCP violation that polymorphism solves.

What is a “varargs” function and how does it count in terms of arity?
?
A vararg function accepts a variable number of same-typed arguments (e.g., String.format(String fmt, Object... args)). From the arity perspective, the varargs parameter counts as a single argument, so format(fmt, args) is dyadic (acceptable), not polyadic.

What is the difference between a command and a query in CQS?
?
A command changes system state and returns void (e.g., setAttribute(name, value)). A query returns information without changing state (e.g., attributeExists(name)). CQS says never mix them: a function that sets a value should not also return whether it succeeded.

Give an example of a function name that violates the “consistent lexicon” rule.
?
Using fetchUser(), retrieveOrder(), and getProduct() in the same codebase — all three do the same thing (a DB lookup) but use different verbs. Readers must investigate each one. The fix: pick one verb (findUser(), findOrder(), findProduct()) and use it everywhere for DB lookups.

What does the “Rule of Three” say about when to apply DRY?
?
Wait until a pattern appears three times before extracting it. The first time you write something, just write it. The second time, note the duplication. The third time, extract. This avoids premature abstraction of things that are merely similar today but may diverge conceptually later.

What makes assertEquals(expected, actual, delta) a triadic function to avoid?
?
Three arguments increase the number of test cases needed (each argument can be wrong), create ordering confusion (is expected first or second?), and force callers to stop and think about argument semantics. When a triadic cannot be avoided, the argument order must be universally agreed upon.

What is wrong with public int deleteRecord(int id) returning an ErrorCodes value?
?
The caller must check the error code immediately after the call, leading to deeply nested if blocks. Error codes can also be silently ignored. Exceptions cannot be quietly ignored — they propagate up until caught, forcing the caller to acknowledge the failure.

What is an “argument list” and how is it different from a polyadic function?
?
An argument list (varargs) takes an arbitrary number of arguments of the same type (e.g., printf(String format, Object... args)). Because the list is a single concept (a sequence of values), it counts as one argument. A polyadic function takes 4+ arguments of different types — those should be wrapped in an argument object.

Why should functions be treated as the primary unit of organization?
?
Functions are the first-level decomposition of a program. Every system-level problem maps to how functions are structured — readability, testability, changeability. A system of clean, well-named, single-purpose functions is self-documenting and change-resilient. Messy functions cascade into messy systems.

Total Cards: 28
Review Time: ~18 minutes
Priority: HIGH
Last Updated: 2026-04-14