Clean Code - Uncle Bob / Lesson 2
Where Did the Moon Come From?
Theories of Lunar Origin
- The moon's origin is complex; initial theories included it being a captured asteroid or having bubbled out from Earth.
- The moon's orbit is not aligned with Earth's equator but rather with the solar system, suggesting it may not have originated from Earth.
- A circular orbit of the moon contradicts the idea of it being a captured body, which typically has an elliptical orbit.
- The moon's composition closely resembles Earth's, except for its lack of iron, raising questions about how it could have formed from Earth.
- The moon is tidally locked to Earth, indicating that its orbit began much closer and was later pushed outward.
Current Theory on Lunar Formation
- Scientists propose that a Mars-sized body formed at a stable point in Earth's orbit and collided with Earth around 4.5 billion years ago.
- This collision melted both bodies, leading to the formation of a ring composed mainly of lightweight silicates that coalesced into the moon.
- Angular momentum transfer during this process caused the moon to move away from Earth and circularize its orbit.
- In early history, days on Earth were only six hours long; as time passed, angular momentum changes led to longer days and increased distance between Earth and the moon.
- It will take approximately eleven billion years for Earth to become tidally locked to the moon; however, this timeframe is not a concern for current generations.
The Purpose of Comments in Code
Understanding Code Documentation
- Comments are essential for explaining code functionality when code cannot self-explain effectively.
- Early programming languages like Fortran had limitations (e.g., six-character name limits), making self-documentation challenging.
- Modern programming languages offer rich features such as long names and structured elements (classes, variables), enhancing code clarity.
Critique of Poor Coding Practices
- An example of poorly written code highlights significant issues in documentation practices within software development environments.
Commenting in Code: The Good, the Bad, and the Ugly
Introduction to the Problem
- The speaker expresses frustration over a comment made by a colleague who irresponsibly checked in code with an excuse for not fixing it later.
- Emphasizes that while emergency fixes are acceptable, they should not be accompanied by excuses or poor practices.
The Role of Comments
- Introduces the topic of comments in code, stating that good comments can be helpful but bad comments can obscure understanding.
- Critiques the notion that all comments are inherently good; many were taught to believe that more comments equate to better code quality.
Misconceptions About Comments
- Discusses how measuring code quality by counting comments leads to absurdities like overly simplistic or unnecessary comments (e.g., "AI++ // increment I").
- Argues that every comment represents a failure to express oneself clearly in code; thus, programmers should strive for clarity without relying on comments.
The Deterioration of Comments
- Notes that comments often degrade over time and become misleading as they are rarely maintained.
- Highlights how IDE color schemes often make comments easy to ignore, leading developers to overlook them when working on code.
Consequences of Poor Commenting Practices
- Describes how outdated or incorrect comments can lead developers astray, potentially causing errors if followed blindly.
- Raises concerns about maintaining obsolete comments instead of deleting them or updating them as necessary.
Cleaning Up Code vs. Commenting
- Warns against using comments as a crutch for poorly written code; emphasizes the importance of cleaning up code instead.
- Suggests focusing efforts on making the code itself clear rather than compensating with excessive commenting.
Examples and Acceptable Comments
- Provides an example where a complex boolean expression could be simplified with clearer function names instead of relying on explanatory comments.
Understanding Design Patterns and Code Comments
The Importance of Design Patterns
- The speaker discusses the significance of a comment in code that indicates it returns an instance of the responder being tested, highlighting the use of design patterns.
- The singleton design pattern is introduced, with a recommendation for attendees to read the "Design Patterns" book, emphasizing its importance in understanding established coding concepts.
- The speaker notes that while the book does not present new ideas, it provides names and canonical forms for existing concepts, facilitating better communication among developers.
- Familiarity with design patterns allows developers to discuss solutions at a higher level of abstraction, making it easier to conceptualize designs like visitor or decorator patterns.
- Despite some modern opinions dismissing design patterns as outdated, the speaker argues they remain essential knowledge for effective programming.
Analyzing Code Comments
- A specific example illustrates how naming conventions in code can be influenced by design patterns; comments serve as clarifications when naming cannot be improved.
- Another informative comment explains what a regular expression matches. However, it's noted that this regex may match more than stated, indicating potential misleading information in comments.
- Regular expressions are described as complex and difficult to understand; thus, having comments explaining their purpose is deemed beneficial but must be accurate.
Evaluating Comment Quality
- A comment about Java's compareTo function uses an imperial we phrasing which could be clearer but conveys intent regarding type checking effectively.
- The discussion shifts to race conditions in multi-threaded programming; creating many threads isn't an effective way to induce race conditions without proper synchronization techniques.
Optical Illusions in Code
- The speaker critiques a method used to create race conditions as ineffective and suggests better practices for testing concurrency issues through proper thread management.
Understanding the Challenges of Code Comments
The Double-Edged Sword of Comments
- Comments can mislead readers if they are incorrect, causing them to overlook the actual code. This highlights the importance of accurate commenting.
Expressiveness in Code
- Some code is inherently difficult to express clearly. A warning about a test that could generate 10 million lines illustrates this challenge.
Disabled Tests and Their Implications
- The use of underscores to disable tests in JUnit indicates potential performance issues, emphasizing the need for clear comments regarding disabled tests.
Thread Safety Concerns
- SimpleDateFormat is not thread-safe due to static variables, which can lead to concurrent update problems. It's crucial to document such limitations as a defensive measure.
Evolving Perspectives on TODO Comments
- Initially seen as useful, TODO comments have become problematic as they often remain unaddressed. A new rule suggests that these comments should be resolved or deleted before code submission.
The Importance of Clear Documentation
Semantic Significance of Functions
- The trim function's significance within an algorithm should be highlighted through comments, ensuring it’s not overlooked by developers.
JavaDocs: When Are They Necessary?
- JavaDocs are beneficial for external APIs but may be unnecessary for internal team projects where code structure is already understood among team members.
Identifying Bad Comment Practices
Misleading Comments in Exception Handling
- A comment in a catch block fails to clarify what happens when an exception occurs, leading to confusion about default values being loaded.
Ineffective Descriptions and Readability Issues
Comments in Code: Are They Necessary?
The Role of Comments in Code
- The speaker critiques the use of comments, particularly JavaDocs, arguing that they often do not add value and can be redundant when variable names are descriptive enough.
- The term "container" is inconsistently used, leading to confusion; the speaker emphasizes that comments should clarify rather than complicate understanding.
- Many comments are deemed unnecessary, with the speaker suggesting that they stem from a misguided belief that all code must be commented on.
- The speaker questions coding standards that mandate comments for every function or class, labeling such requirements as counterproductive and leading to poor-quality commentary.
JavaDoc and Source Control Systems
- JavaDocs are intended to generate HTML documentation; however, removing excessive comments does not significantly affect the output quality.
- Historical practices of including journal comments at the beginning of source files are outdated due to modern source control systems like Git.
- Deleting unnecessary comments from code is encouraged since version control retains all historical changes without cluttering current code.
Understanding Instance Variables and Comment Clutter
- The speaker expresses frustration over obvious comments about instance variables, asserting that experienced programmers already understand these concepts without needing reminders.
- A specific example from Tomcat illustrates how unclear comments can lead to confusion; extracting meaningful variable names improves readability without relying on vague commentary.
Effective Use of Comments
- While some emphasis in comments can be useful for drawing attention to critical information, overuse diminishes their effectiveness and leads to cluttered code.
- Historical techniques for tracking closing braces through commenting are now considered unnecessary due to advancements in IDE features.
The Dangers of Commented-Out Code
Code Comments and Best Practices
Importance of Code Clarity
- The speaker emphasizes the importance of not checking in commented-out code, advocating for clarity and cleanliness in code submissions.
- A specific example is given regarding a variable
header pause, which the speaker finds unnecessary and plans to delete, reinforcing the idea that extraneous code should be removed.
Effective Commenting Techniques
- The speaker critiques excessive use of HTML macros in Java documentation, arguing that comments should be easily readable within the code itself rather than obscured by formatting.
- It is highlighted that comments should enhance understanding without requiring external tools; readability within the source file is paramount.
Guidelines for Writing Comments
- A fundamental rule presented: comments should only refer to the immediate code context to avoid becoming outdated or misleading as code evolves.
- The speaker advises against including "where used" lists in comments due to their tendency to change frequently, which can lead to inaccuracies.
Philosophy on Commenting
- While acknowledging that comments are not inherently bad, the speaker stresses that they should not be written by default; instead, developers should strive for self-explanatory code.
- A good reason must exist for writing a comment; if the code cannot convey its purpose clearly, then a comment may be warranted.
Analyzing Source File Sizes
Study Overview
- The speaker conducted a study analyzing seven projects' file sizes to understand typical source file lengths and structures across different coding projects.
Findings from Project Analysis
- JUnit serves as an example with approximately 6,000 lines of code. Its modules vary significantly in size but generally average around 20–50 lines each.
Comparison Across Projects
- Fitness project has about 50,000 lines of code yet maintains a similar module structure as JUnit despite its larger size. This challenges assumptions about larger projects having more complex structures.
Variability in File Structures
- TestNG shows significant variability with an average module size around 40 lines but includes some exceptionally large files (up to 1,500 lines), indicating irregularity in file sizes compared to other projects analyzed.
Conclusion on File Size Correlation
Understanding Code Structure and Naming Conventions
The Importance of Line Length in Code
- Discusses the style that can be imposed on a coding system, emphasizing the average file size of about 50 lines, with most files being under 100 lines.
- Introduces a statistical analysis of line lengths across different projects, highlighting an interesting correlation among them.
- Describes a histogram showing the distribution of line lengths, noting that many lines are blank and that there is a rapid decline in longer lines.
- Observes that all seven analyzed Java applications exhibit similar clustering around 30 to 35 lines of code, indicating a preference for shorter line lengths.
- Argues that despite larger screens, the preferred line length remains around 30 to 40 characters, suggesting screen size does not influence this distribution.
Guidelines for Effective Coding Practices
- Recommends keeping line lengths between 30 to 40 characters and setting a maximum limit (e.g., 150 characters) to avoid forcing readers to scroll horizontally.
- Emphasizes the importance of readability in code and warns against hiding information by exceeding recommended line lengths.
Naming Conventions in Programming
- Shifts focus to naming conventions in programming, noting how early limitations on name length have been lifted allowing for more descriptive names.
- Highlights the significance of naming various elements within software development (files, directories, classes), stressing the need for good naming practices due to their prevalence.
Rules for Naming Variables
- Introduces Tim Ottinger's rules for naming variables which emphasize revealing intent through names.
- Questions what constitutes an appropriate variable name length; single-letter names may suffice in small scopes like loops (e.g., 'i' in
forloops).
Proportionality in Variable Naming
- Suggests that variable name length should correlate with scope size: short names are acceptable in small scopes while longer scopes require more descriptive names.
Naming Conventions in Programming
Variable Naming and Scope
- Variables should have a name length proportional to their scope; global variables may require longer names due to their extensive reach.
- The rule for function naming is the opposite of variable naming; larger scopes necessitate shorter function names.
Function Naming Principles
- As the scope of a function increases, its name should become shorter to reflect its high-level abstraction and frequent usage.
- Functions within large scopes are called from various locations, thus requiring concise names that encapsulate broader functionality.
Hierarchical Naming Structure
- Method names within classes tend to be longer as they become more specific; private functions called by public ones will have even longer names.
- The inverse relationship between function name length and scope size applies similarly to class naming conventions.
Class Naming Guidelines
- Class names at the global level typically consist of single words, while derived and inner classes use multiple words as their scope narrows.
Importance of Descriptive Names
- A well-named variable or function can provide clarity about its purpose; for example, a function that scans lists for specific elements can be named accordingly.
The Role of Context in Naming
Clarity Through Contextual Names
- Effective naming not only clarifies individual functions but also conveys the broader context of the program, enhancing overall understanding.
Optical Illusions in Code
- Programmers must remain vigilant against optical illusions in code that can obscure differences between similar-looking characters or symbols.
Modern Practices in Variable Naming
Prefix Usage Evolution
- The practice of using prefixes (e.g., 'a' for local variables, 'd' for arguments, 'i' for instance variables) has diminished with advancements in IDE capabilities that clarify variable types.
Avoiding Noise Words
Understanding Function Naming and Code Review Practices
Confusion in Function Naming
- The first function,
get active account, returns a single active account, while the second function,get active accounts, suggests multiple accounts. This inconsistency raises questions about what the first function actually returns.
- The third function,
get active account info, is even more perplexing as it returns a list of accounts. Poorly chosen names lead to confusion regarding their functionality.
Importance of Clear Naming Conventions
- A specific example is given with the name
jigna minam's, which represents a generation timestamp but is difficult to pronounce. This highlights the need for clear and understandable naming conventions in programming.
Benefits of Pair Programming
- The speaker discusses how pairing allows for knowledge sharing among programmers. Despite its advantages, many do not engage in pair programming frequently.
- Code reviews are mentioned as a common practice; however, they can be inefficient compared to pair programming. A code review should ideally take a significant amount of time relative to the time spent writing the module.
Time Investment in Code Reviews vs Pair Programming
- If reviewing a module that took five hours requires only 15 minutes, it indicates superficial checking rather than thorough understanding. Effective reviews necessitate walking through the author's reasoning and code structure.
- Pair programming takes about the same time as reviewing but involves active participation from both programmers, leading to better knowledge transfer and contribution.
Clarifying Terminology: Noise Words in Exceptions
- The term "exception" appears frequently across various types (e.g., IllegalStateException). It does not constitute a noise word since it serves as a base class descriptor for derived exceptions.
Conclusion on Pair Programming Discussion