loader

Chapter 3 of “Clean Code” dives into how to write functions well. Think of functions as the workhorses of your code. If they’re well-organized and focused, your code is easier to understand, test, and maintain. This chapter lays out the key principles for making your functions truly clean.

Chapter 3 – Functions

  • Small!: The first, and arguably most important, point is that functions should be small. The shorter they are, the easier it is to grasp what they do. Aim for functions that are only a few lines long.
    • Blocks and Indenting: This reinforces the “small” idea. Blocks within if, else, while, etc., should ideally be only one line long, usually a call to another function with a descriptive name. This keeps the enclosing function small and readable.
  • Do One Thing: A function should have one, and only one, responsibility. If a function tries to do multiple things, it becomes harder to understand, test, and reuse. If you can logically break down a function into separate actions, it’s likely doing more than one thing.
    • Sections within Functions: If you find distinct sections within a function, it’s a sign that the function is doing more than one thing and those sections should probably be extracted into their own functions.
  • One Level of Abstraction per Function: All statements within a function should operate at the same level of detail. High-level concepts shouldn’t be mixed with low-level implementation details. This makes the code read more like a narrative.
    • Reading Code from Top to Bottom: The Stepdown Rule: Code should read like a well-written article, with each function followed by those at the next level of abstraction. This makes it easy to follow the flow of logic as you read down the code.
  • Switch Statements: switch statements inherently violate the “do one thing” principle as they handle multiple cases. The book suggests using polymorphism to handle different cases instead, often by creating an abstract factory to determine the appropriate object.
  • Use Descriptive Names: Just like variables, functions need clear and descriptive names that convey their purpose. Choose names that explain what the function does and any side effects it might have. Use consistent naming conventions.
  • Function Arguments: Ideally, functions should have as few arguments as possible.
    • Common Monadic Forms: A function with one argument is often acceptable, especially if it’s asking a question about the argument (boolean fileExists("name")) or transforming it (InputStream fileOpen("name")).
    • Flag Arguments: Boolean arguments that dictate different behavior within a function are a sign that the function is doing more than one thing. Avoid them.
    • Dyadic Functions: Functions with two arguments are harder to understand than monadic functions. They should be used sparingly and only when the two arguments naturally belong together.
    • Triads: Functions with three arguments are significantly harder to grasp and should be avoided if possible.
    • Argument Objects: If a function needs multiple arguments that logically belong together, consider wrapping them into a single, well-named object.
    • Argument Lists: Variable argument lists (like printf) should be used sparingly and only when their use is very clear.
    • Verbs and Keywords: Choose function names that clearly indicate what the function does and the intent of the arguments. For monadic functions, the function and argument should form a clear verb/noun phrase (e.g., deletePage(page)).
  • Have No Side Effects: Functions should do what their name says and nothing else. Hidden side effects (modifying state that isn’t obvious from the function name) can lead to unexpected behavior and make code difficult to debug.
    • Output Arguments: Output arguments are often counterintuitive. Prefer using the return value to convey the result of a function.
  • Command Query Separation: Functions should either be commands (performing an action) or queries (returning information), but not both. Mixing these responsibilities can lead to confusion.
  • Prefer Exceptions to Returning Error Codes: Using exceptions allows you to separate error handling logic from the normal flow of the code, resulting in cleaner code. Returning error codes often requires the caller to immediately check for errors, cluttering the main logic.
    • Extract Try/Catch Blocks: To further clean up code, extract the try, catch, and finally blocks into their own functions.
    • Error Handling Is One Thing: A function should ideally either handle errors or do its primary task, but not both.
    • The Error.java Dependency Magnet: Be cautious about how you define your error handling. Reusing a single Error enum or class across many modules can create unwanted dependencies.
  • Don’t Repeat Yourself (DRY): While a general principle, it strongly applies to functions. Well-structured, small functions naturally promote code reuse, reducing redundancy and improving maintainability.
  • Structured Programming: While acknowledging historical debates, the book advocates for small functions with single entry and exit points to enhance readability. Avoid goto statements.
  • How Do You Write Functions Like This?: The book emphasizes that you likely won’t write perfectly small, well-structured functions on the first try. It’s an iterative process of writing, refactoring, and continuously improving the clarity and organization of your code.
  • Conclusion: Writing clean functions is key to writing clean code. By keeping them small, focused, and well-named, you make your code easier to understand, test, and maintain, ultimately leading to more robust and successful software.
  • SetupTeardownIncluder: This is a brief example illustrating the principles discussed in the chapter, showing how to refactor a larger function into smaller, more manageable, and readable parts.

Functions are where code either stays clean or starts to fall apart. Chapter 3 shows that writing great functions isn’t a one-and-done task but an ongoing discipline of clarity and refinement. If this breakdown helped, follow the series for more. One chapter a day, each one packed with insights. And I’d love to hear how you approach clean functions. Drop a comment or share your favorite rule.