More on this book
Community
Kindle Notes & Highlights
In his book Clean Code, Robert Martin takes a more negative view of comments: ... comments are, at best, a necessary evil. If our programming languages were expressive enough, or if we had the talent to subtly wield those languages to express our intent, we would not need comments very much — perhaps not at all. The proper use of comments is to compensate for our failure to express ourselves in code.... Comments are always failures. We must have them because we can’t always figure out how to express ourselves without them, but their use is not a cause for celebration.
This results in long names such as isLeastRelevantMultipleOfNextLargerPrimeFactor. Even with all these words, names like this are cryptic and provide less information than a well-written comment.
I worry that Martin’s philosophy encourages a bad attitude in programmers, where they avoid comments so as not to seem like failures. This could even result in good designers coming under false criticism: “What’s wrong with your code that it requires comments?”
Well-written comments are not failures. They increase the value of code and serve a fundamental role in defining abstractions and managing system complexity.
The reason for writing comments is that statements in a programming language can’t capture all of the important information that was in the mind of the developer when the code was written.
Comments augment the code by providing information at a different level of detail.
When documenting a variable, think nouns, not verbs. In other words, focus on what the variable represents, not how it is manipulated.
If you want code that presents good abstractions, you must document those abstractions with comments.
The first step in documenting abstractions is to separate interface comments from implementation comments.
Interface comments provide information that someone needs to know in order to use a class or method; they define the abstraction. Implementation comments describe how a class or method work...
This highlight has been truncated due to consecutive passage length restrictions.
When documenting variables, focus on what the variable represents, not how it is manipulated in the code.
The goal of comments is to ensure that the structure and behavior of the system is obvious to readers, so they can quickly find the information they need and make modifications to the system with confidence that they will work.
Good names are a form of documentation:
Good names have two properties: precision and consistency.
Overall, I would argue that readability must be determined by readers, not writers.
Many developers put off writing documentation until the end of the development process, after coding and unit testing are complete. This is one of the surest ways to produce poor quality documentation.
When the code is done, the comments are also done. There is never a backlog of unwritten comments.
Comments serve as a canary in the coal mine of complexity. If a method or variable requires a long comment, it is a red flag that you don’t have a good abstraction.
in tactical programming, the primary goal is to get something working quickly, even if that results in additional complexity; in strategic programming, the most important goal is to produce a great system design.
If you want to maintain a clean design for a system, you must take a strategic approach when modifying existing code.
To achieve this goal, you must resist the temptation to make a quick fix. Instead, think about whether the current system design is still the best one, in light of the desired change.
Code reviews provide another opportunity for enforcing conventions and for educating new developers about the conventions.
When in Rome ... The most important convention of all is that every developer should follow the old adage “When in Rome, do as the Romans do.”
Don’t change existing conventions. Resist the urge to “improve” on existing conventions.
Your new idea may indeed be better, but the value of consistency over inconsistency is almost always greater than the value of one approach over another.
Obscurity occurs when important information about a system is not obvious to new developers.
To make code obvious, you must ensure that readers always have the information they need to understand it.
Before using implementation inheritance, consider whether an approach based on composition can provide the same benefits.
Tests, particularly unit tests, play an important role in software design because they facilitate refactoring.
Although I am a strong advocate of unit testing, I am not a fan of test-driven development. The problem with test-driven development is that it focuses attention on getting specific features working, rather than finding the best design.
One place where it makes sense to write the tests first is when fixing bugs. Before fixing a bug, write a unit test that fails because of the bug.
so they add clutter to the class’s interface without providing much functionality. It’s better to avoid getters and setters (or any exposure of implementation data) as much as possible.
This is true even for experienced developers. If you start making changes based on intuition, you’ll waste time on things that don’t actually improve performance, and you’ll probably make the system more complicated in the process.
The key idea is to design the code around the critical path.
try to minimize the number of special cases you must check.
The most important overall lesson from this chapter is that clean design and high performance are compatible.
Complicated code tends to be slow because it does extraneous or redundant work.
Shallow classes are often the result of treating too many things as important.
This mistake leads to situations where important information is hidden, or important functionality is not available so developers must continually recreate it. This kind of mistake impedes developer productivity and leads to unknown unknowns.