The Art of Readable Code - Summary

  • Theory In Practice: The Art of Readable Code

  • Presents simple and practical techniques for writing better code.

  • Authors: Dustin Boswell and Trevor Foucher.

  • Core Idea: Write code that minimizes the time it takes someone else to understand it, including yourself in the future.

  • Focuses on basic principles applicable every time you write code, using examples from various languages.

  • Key areas covered include naming, commenting, formatting, loops, logic, variables, and code reorganization.

  • Includes writing effective test code.

  • Authors’ Background:

    • Dustin Boswell: CalTech graduate, former Google employee (web crawling infrastructure, ad programs).

    • Trevor Foucher: Over a decade at Microsoft and Google (Windows, security products, ad programs, search infrastructure).

  • This book is about how to write code that’s highly readable.

  • The key idea in this book is that code should be easy to understand. Specifically, your goal should be to minimize the time it takes someone else to understand your code.

  • This book explains this idea and illustrates it with lots of examples from different languages, including C++, Python, JavaScript, and Java.

  • Avoided advanced language features, so even if you don’t know all these languages, it should still be easy to follow along.

  • The concepts of readability are mostly language-independent, anyhow.

  • Each chapter dives into a different aspect of coding and how to make it “easy to understand.” The book is divided into four parts:

    • Surface-level improvements

    • Naming, commenting, and aesthetics—simple tips that apply to every line of your codebase

    • Simplifying loops and logic
      -Ways to refine the loops, logic, and variables in your program to make them easier to understand

    • Reorganizing your code

    • Higher-level ways to organize large blocks of code and attack problems at the function level

    • Selected topics
      -Applying “easy to understand” to testing and to a larger data structure coding example

  • Book is intended to be a fun, casual read.

  • Chapters are ordered by “difficulty”: basic topics are at the beginning, and more advanced topics are at the end.

  • Each chapter is self-contained and can be read in isolation. So feel free to skip around if you’d like.

  • Code Should Be Easy to Understand

    • Code should be easy to understand. This is the most important guiding principle when deciding how to write code.

  • What Makes Code “Better?”

    • Programming decisions are often based on gut feel and intuition.

  • The Fundamental Theorem of Readability

    • The most important metric for code readability is minimizing the time it takes for someone else to understand it.

    • Understanding means being able to make changes, spot bugs, and understand interactions with other code.

  • Is Smaller Always Better?

    • Less code is generally better, but minimizing time-till-understanding is the better goal.

    • Comments can improve understanding even if they add code.

    • Example:

  // Fast version of "hash = (65599 * hash) + c"
  hash = (hash << 6) + (hash << 16) - hash + c;
  • Does Time-Till-Understanding Conflict with Other Goals?

    • The goal of easy readability can align well with other goals, such as efficiency, good architecture, and testability.

  • The Hard Part

    • Requires conscious effort to consider outsider’s understanding.

    • This can lead to better code along with fewer bugs by adopting the goal of easy to read.

  • Surface-Level Improvements

    • Naming, commenting, and aesthetics are “surface-level” improvements.

    • They’re easy to apply and make code more readable.

    • Affect every line of code in codebase.

    • Great names, well-written comments, and clean whitespace improve readability.

  • Packing Information into Names

    • A name is a tiny comment.

    • Pack information into your names.

    • Vague names should be avoided.

  • Specific Word Choices

    • Choose specific and non-empty words.

    • Example: GetPage(url) could be FetchPage() or DownloadPage().

    • Use a thesaurus to find more descriptive alternatives.

    • Be clear and precise instead of cute.

  • Avoid Generic Names

    • Avoid generic names like tmp, retval, and foo, unless they carry specific meaning.

    • Use retval only when its meaning is obvious.

  • Loop Iterators

    • i, j, iter, it are commonly used as loop iterators.

    • Can use more precise names than i, j, and k.

    • Example club_i, members_i, users_i or more succinctly ci, mi, ui.

  • Concrete over Abstract Names

    • Describe elements concretely, not abstractly.

    • ServerCanStart() (abstract) vs. CanListenOnPort() (concrete).

  • Attaching Extra Information

    • Include units in names (e.g., delay_secs, size_mb).

    • Indicate unsafe or unprocessed data (e.g., untrustedUrl, unescaped_comment).

  • Length of Names

    • Shorter names are acceptable for shorter scopes.

    • Avoid project-specific abbreviations if new teammate wouldn’t understand.

  • Name Formatting

    • CamelCase for class names, lower_separated for variable names.

    • Constant values as kConstantName.

    • Class member variables end with an underscore.

  • Misconstrued Names

    • Actively scrutinize names to avoid misinterpretation.

    • Example results = Database.all_objects.filter("year <= 2011")

    • Is filter to pick out or get rid of?

    • For “to pick out," a better name is select().

    • If you want “to get rid of," a better name is exclude().

  • Inclusive Limits

    • Prefer min and max to define limits (e.g., MAX_ITEMS_IN_CART).

  • Inclusive Ranges:

    • Use "first" and "last“ to make it clear it's inclusive

  • Inclusive/Exclusive Ranges:

    • Use “begin" and "end“. Although the word end is a little ambiguous, convention makes it the best choice.

  • Naming Booleans:

    • Use words like "is", "has", "can", or "should" to make it clear.

    • Adding words like is, has, can, or should can make booleans more clear.

  • Matching User Expectations:

    • Beware of conflicting with user expectations about certain words. Example getMean() is an expensive calculation and should be named computeMean().

  • Aesthetics

    • Use consistent layout.

    • Make similar code look similar.

    • Group related lines into blocks.

  • Rearrange Line Breaks:

    • Rearrange line breaks to be consistent and compact.

    • Avoid duplication.

  • Clean Up Irregularity:

    • Use methods to clean up irregularity.

  • Column Alignment:

    • Use column alignment when helpful. It can make mistakes more pronounced.

  • Meaningful Order:

    • Pick a meaningful order and use it consistently.

  • Organize Declarations:

    • Organize declarations into blocks to match organization of thought.

  • Code into Paragraphs:

    • Facilitates navigation from one paragraph to another. Same as written text.

  • Personal Style vs. Consistency:

    • Consistent style is more important than the “right” style.

  • Comments

    • The goal of commenting is to help the reader know as much as the writer did.

  • Knowing What to Comment
    -What NOT to Comment:
    -Facts that can be derived quickly, e.g. Account() followed by //Constructor
    -Just for the sake of commenting
    -Bad Names—Fix the Names Instead

  • Recording Your Thoughts

    • Include “Director Commentary” - valuable insights about the code e.g. code may not look that good but fixing it to do otherwise requires more work

    • Comment the Flaws in Your Code
      -TODO: Stuff I haven’t gotten around to yet
      -FIXME: Known-broken code here
      -HACK: Admittedly inelegant solution to a problem
      -XXX: Danger! major problem here

    • Comment on Your Constants

      • Describe the “story” for what the constant does or why it has that specific value

  • Put Yourself in the Reader’s Shoes

    • Anticipating Likely Questions

    • Advertising Likely Pitfalls

    • “Big Picture” Comments

    • Summary Comments
      -Final Thoughts—Getting Over Writer’s Block

    • Just document what you’re thinking e.g. oh crap etc… and just go from there

  • Making Comments Precise and Compact
    -Keep Comments Compact
    -Avoid Ambiguous Pronouns
    -Polish Sloppy Sentences
    -Describe Function Behavior Precisely
    -Use Input/Output Examples That Illustrate Corner Cases
    -State the Intent of Your Code
    -“Named Function Parameter” Comments
    -Use Information-Dense Words

  • Simplifying Loops and Logic
    -Every time you see a complicated loop, a giant expression, or a large number of variables, this adds to the mental baggage in your head. It requires you to think harder and remember more. This is exactly the opposite of “easy to understand."
    -When code has a lot of mental baggage, bugs are more likely to go unnoticed, the code becomes harder to change, and it’s just less fun to work with.

  • Making Control Flow Easy to Read
    -Make all your conditionals, loops, and other changes to control flow as “natural” as possible—written in a way that doesn’t make the reader stop and reread your code
    -The Order of Arguments in Conditionals
    -Prefer dealing with the positive case first instead of the negative—e.g., if (debug) instead of if (!debug).
    -Prefer dealing with the simpler case first to get it out of the way., to make it easy to read
    -There are number of coding constructs that are not readable.
    -do/while: Most of the time don't use it as it is confusing to read
    -goto: avoid when possible

    • minimize nesting, deep down you have to pop the nested code and remember what's inside

  • Breaking Down Giant Expressions
    -

  • Theory In Practice: The Art of Readable Code

  • Presents simple and practical techniques for writing better code, emphasizing the importance of code readability in software development.

  • Authors: Dustin Boswell and Trevor Foucher, bring extensive experience from Google and Microsoft to provide actionable advice.

  • Core Idea: Write code that minimizes the time it takes someone else to understand it, including yourself in the future. This principle is crucial for maintainability and collaboration.

  • Focuses on basic principles applicable every time you write code, using examples from various languages like C++, Python, JavaScript, and Java to illustrate universal concepts.

  • Key areas covered include naming conventions, commenting strategies, formatting practices, loop optimization, logical simplification, variable usage, and code reorganization techniques to enhance understanding.

  • Includes guidance on writing effective test code, ensuring that tests are as readable and maintainable as the application code itself.

  • Authors’ Background:

    • Dustin Boswell: CalTech graduate, former Google employee with experience in web crawling infrastructure and ad programs, bringing a wealth of knowledge in scalable systems.

    • Trevor Foucher: Over a decade at Microsoft and Google, working on Windows, security products, ad programs, and search infrastructure, providing insights into enterprise-level code practices.

  • This book is about how to write code that’s highly readable, making it accessible to developers of all skill levels.

  • The key idea in this book is that code should be easy to understand. Specifically, your goal should be to minimize the time it takes someone else to understand your code, reducing onboarding time and improving team efficiency.

  • This book explains this idea and illustrates it with lots of examples from different languages, including C++, Python, JavaScript, and Java, ensuring broad applicability.

  • Avoided advanced language features, so even if you don’t know all these languages, it should still be easy to follow along, focusing on fundamental coding practices.

  • The concepts of readability are mostly language-independent, anyhow, making the book relevant regardless of the reader's programming language of choice.

  • Each chapter dives into a different aspect of coding and how to make it “easy to understand.” The book is divided into four parts:

    • Surface-level improvements: Naming, commenting, and aesthetics—simple tips that apply to every line of your codebase, improving code clarity and maintainability.

    • Simplifying loops and logic: Ways to refine the loops, logic, and variables in your program to make them easier to understand, reducing cognitive load and potential errors.

    • Reorganizing your code: Higher-level ways to organize large blocks of code and attack problems at the function level, promoting modularity and reusability.

    • Selected topics: Applying “easy to understand” to testing and to a larger data structure coding example, demonstrating the principles in practical scenarios.

  • Book is intended to be a fun, casual read. Approachable and engaging for developers seeking practical advice.

  • Chapters are ordered by “difficulty”: basic topics are at the beginning, and more advanced topics are at the end, allowing readers to progressively enhance their coding skills.

  • Each chapter is self-contained and can be read in isolation. So feel free to skip around if you’d like, catering to individual learning preferences.

  • Code Should Be Easy to Understand

    • Code should be easy to understand. This is the most important guiding principle when deciding how to write code, ensuring long-term maintainability and collaboration.

  • What Makes Code “Better?”

    • Programming decisions are often based on gut feel and intuition, but this book provides a more structured approach to evaluating code quality.

  • The Fundamental Theorem of Readability

    • The most important metric for code readability is minimizing the time it takes for someone else to understand it. Reducing this time improves productivity and reduces errors.

    • Understanding means being able to make changes, spot bugs, and understand interactions with other code, essential for effective software development.

  • Is Smaller Always Better?

    • Less code is generally better, but minimizing time-till-understanding is the better goal. Prioritizing clarity over brevity.

    • Comments can improve understanding even if they add code. Strategic commenting enhances code comprehension.

    • Example:

// Fast version of "hash = (65599 * hash) + c"
hash = (hash << 6) + (hash << 16) - hash + c;
  • Does Time-Till-Understanding Conflict with Other Goals?

    • The goal of easy readability can align well with other goals, such as efficiency, good architecture, and testability, creating a holistic approach to software development.

  • The Hard Part

    • Requires conscious effort to consider outsider’s understanding. Developers must actively think about how others will perceive their code.

    • This can lead to better code along with fewer bugs by adopting the goal of easy to read. Readable code is easier to debug and less prone to errors.

  • Surface-Level Improvements

    • Naming, commenting, and aesthetics are “surface-level” improvements. These are the easiest to implement and have an immediate impact on readability.

    • They’re easy to apply and make code more readable. Consistent application of these principles improves overall code quality.

    • Affect every line of code in codebase. Ensuring consistency across the entire project.

    • Great names, well-written comments, and clean whitespace improve readability. These elements contribute to a more understandable codebase.

  • Packing Information into Names

    • A name is a tiny comment. Effective naming reduces the need for excessive commenting.

    • Pack information into your names. Names should convey as much information as possible about the variable or function.

    • Vague names should be avoided. Clarity in naming is essential for understanding code quickly.

  • Specific Word Choices

    • Choose specific and non-empty words. Select names that accurately reflect the purpose of the code element.

    • Example: GetPage(url) could be FetchPage() or DownloadPage(). More descriptive names improve clarity.

    • Use a thesaurus to find more descriptive alternatives. Expanding vocabulary enhances the ability to name elements precisely.

    • Be clear and precise instead of cute. Professionalism in naming avoids confusion and promotes understanding.

  • Avoid Generic Names

    • Avoid generic names like tmp, retval, and foo, unless they carry specific meaning. Use meaningful names to enhance understanding.

    • Use retval only when its meaning is obvious. Overuse of generic names obscures the purpose of the code.

  • Loop Iterators

    • i, j, iter, it are commonly used as loop iterators. While common, these can sometimes be unclear.

    • Can use more precise names than i, j, and k. More descriptive names improve readability.

    • Example club_i, members_i, users_i or more succinctly ci, mi, ui. Using context-specific names helps understand the code faster.

  • Concrete over Abstract Names

    • Describe elements concretely, not abstractly. Concrete names provide more immediate understanding.

    • ServerCanStart() (abstract) vs. CanListenOnPort() (concrete). The latter provides more specific information.

  • Attaching Extra Information

    • Include units in names (e.g., delay_secs, size_mb). This avoids confusion about the units being used.

    • Indicate unsafe or unprocessed data (e.g., untrustedUrl, unescaped_comment). Awareness of data state prevents errors.

  • Length of Names

    • Shorter names are acceptable for shorter scopes. Within small functions, brevity can be acceptable.

    • Avoid project-specific abbreviations if new teammate wouldn’t understand. Clarity for all team members is crucial.

  • Name Formatting

    • CamelCase for class names, lower_separated for variable names. Consistent formatting improves readability.

    • Constant values as kConstantName. Standard prefixes help identify constants.

    • Class member variables end with an underscore. This convention distinguishes member variables.

  • Misconstrued Names

    • Actively scrutinize names to avoid misinterpretation. Prevent ambiguity by carefully choosing names.

    • Example results = Database.all_objects.filter("year <= 2011")

    • Is filter to pick out or get rid of? The name should clearly indicate the operation.

    • For “to pick out," a better name is select(). Improves clarity.

    • If you want “to get rid of," a better name is exclude(). Clearer indication of purpose.

  • Inclusive Limits

    • Prefer min and max to define limits (e.g., MAX_ITEMS_IN_CART). These terms clearly define boundaries.

  • Inclusive Ranges:

    • Use "first" and "last“ to make it clear it's inclusive, leaving no room for misinterpretation

  • Inclusive/Exclusive Ranges:

    • Use “begin" and "end“. Although the word end is a little ambiguous, convention makes it the best choice.

  • Naming Booleans:

    • Use words like "is", "has", "can", or "should" to make it clear. These prefixes clarify the boolean's meaning.

    • Adding words like is, has, can, or should can make booleans more clear, enhancing code readability

  • Matching User Expectations:

    • Beware of conflicting with user expectations about certain words. Aligning with common understanding prevents confusion.

    • Example getMean() is an expensive calculation and should be named computeMean(). This alerts users to the computational cost.

  • Aesthetics

    • Use consistent layout. Uniform formatting enhances readability.

    • Make similar code look similar. Consistent visual cues aid understanding.

    • Group related lines into blocks. Improves visual structure and comprehension.

  • Rearrange Line Breaks:

    • Rearrange line breaks to be consistent and compact. Consistent line breaks improve visual flow.

    • Avoid duplication. Reduces redundancy and potential errors.

  • Clean Up Irregularity:

    • Use methods to clean up irregularity. Consistent code is easier to understand and maintain.

  • Column Alignment:

    • Use column alignment when helpful. It can make mistakes more pronounced and improves readability in certain contexts.

  • Meaningful Order:

    • Pick a meaningful order and use it consistently. Logical order improves comprehension.

  • Organize Declarations:

    • Organize declarations into blocks to match organization of thought. This reflects the code's logical structure.

  • Code into Paragraphs:

    • Facilitates navigation from one paragraph to another. Same as written text, making it easier to navigate.

  • Personal Style vs. Consistency:

    • Consistent style is more important than the “right” style. Uniformity across the project is crucial for team collaboration.

  • Comments

    • The goal of commenting is to help the reader know as much as the writer did, preventing guessing and saving time.

  • Knowing What to Comment

    • What NOT to Comment:

    • Facts that can be derived quickly, e.g. Account() followed by //Constructor, is redundant.

    • Just for the sake of commenting, avoid unnecessary comments.

    • Bad Names—Fix the Names Instead; clear names reduce the need for comments

  • Recording Your Thoughts

    • Include “Director Commentary” - valuable insights about the code e.g. code may not look that good but fixing it to do otherwise requires more work, explaining the rationale behind decisions.

    • Comment the Flaws in Your Code

    • TODO: Stuff I haven’t gotten around to yet

    • FIXME: Known-broken code here

    • HACK: Admittedly inelegant solution to a problem

    • XXX: Danger! major problem here

    • Comment on Your Constants- Describe the “story” for what the constant does or why it has that specific value, providing context and preventing misuse

  • Put Yourself in the Reader’s Shoes

    • Anticipating Likely Questions; address potential points of confusion

    • Advertising Likely Pitfalls, warn about potential issues

    • “Big Picture” Comments, provide context and overview

    • Summary Comments, provide a summary of complex logic

    • Final Thoughts—Getting Over Writer’s Block

    • Just document what you’re thinking e.g. oh crap etc… and just go from there, capturing the thought process for future reference

  • Making Comments Precise and Compact

    • Keep Comments Compact, concise comments are easier to read

    • Avoid Ambiguous Pronouns, ensure clarity by specifying references

    • Polish Sloppy Sentences, well-written comments improve understanding

    • Describe Function Behavior Precisely, accurate descriptions prevent misuse

    • Use Input/Output Examples That Illustrate Corner Cases, concrete examples clarifies behavior

    • State the Intent of Your Code, explain the purpose

    • “Named Function Parameter” Comments, clarify parameter roles

    • Use Information-Dense Words

  • Simplifying Loops and Logic

    • Every time you see a complicated loop, a giant expression, or a large number of variables, this adds to the mental baggage in your head. It requires you to think harder and remember more. This is exactly the opposite of “easy to understand."

    • When code has a lot of mental baggage, bugs are more likely to go unnoticed, the code becomes harder to change, and it’s just less fun to work with.

  • Making Control Flow Easy to Read

    • Make all your conditionals, loops, and other changes to control flow as “natural” as possible—written in a way that doesn’t make the reader stop and reread your code

    • The Order of Arguments in Conditionals

    • Prefer dealing with the positive case first instead of the negative—e.g., if (debug) instead of if (!debug).

    • Prefer dealing with the simpler case first to get it out of the way., to make it easy to read

    • There are number of coding constructs that are not readable.

    • do/while: Most of the time don't use it as it is confusing to read

    • goto: avoid when possible

    • minimize nesting, deep down you have to pop the nested code and remember what's inside