More on this book
Community
Kindle Notes & Highlights
Read between
January 29 - April 30, 2019
If we all checked-in our code a little cleaner than when we checked it out, the code simply could not rot. The cleanup doesn’t have to be something big. Change one variable name for the better, break up one function that’s a little too large, eliminate one small bit of duplication, clean up one composite if statement.
The name of a variable, function, or class, should answer all the big questions. It should tell you why it exists, what it does, and how it is used.
Programmers must avoid leaving false clues that obscure the meaning of code. We should avoid words whose entrenched meanings vary from our intended meaning.
Beware of using names which vary in small ways.
If names must be different, then they should also mean something different.
Readers shouldn’t have to mentally translate your names into other names they already know.
One difference between a smart programmer and a professional programmer is that the professional understands that clarity is king.
Classes and objects should have noun or noun phrase names like Customer, WikiPage, Account, and AddressParser. Avoid words like Manager, Processor, Data, or Info in the name of a class. A class name should not be a verb.
Methods should have verb or verb phrase names like postPayment, deletePage, or save.
When constructors are overloaded, use static factory methods with names that describe the arguments. For example,
If you follow the “one word per concept” rule, you could end up with many classes that have, for example, an add method. As long as the parameter lists and return values of the various add methods are semantically equivalent, all is well.
It is not wise to draw every name from the problem domain because we don’t want our coworkers to have to run back and forth to the customer asking what every name means when they already know the concept by a different name.
The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that. This
Functions should hardly ever be 20 lines long.
This implies that the blocks within if statements, else statements, while statements, and so on should be one line long. Probably that line should be a function call.
If a function does only those steps that are one level below the stated name of the function, then the function is doing one thing.
So, another way to know that a function is doing more than “one thing” is if you can extract another function from it with a name that is not merely a restatement of its implementation
Functions that do one thing cannot be reasonably divided into sections.
In order to make sure our functions are doing “one thing,” we need to make sure that the statements within our function are all at the same level of abstraction.
The ideal number of arguments for a function is zero (niladic). Next comes one (monadic), followed closely by two (dyadic). Three arguments (triadic) should be avoided where possible. More than three (polyadic) requires very special justification—and then shouldn’t be used anyway.
Flag arguments are ugly. Passing a boolean into a function is a truly terrible practice. It immediately complicates the signature of the method, loudly proclaiming that this function does more than one thing.
Functions should either do something or answer something, but not both.
Returning error codes from command functions is a subtle violation of command query separation.
When you return an error code, you create the problem that the caller must deal with the error immediately.
Functions should do one thing. Error handling is one thing. Thus, a function that handles errors should do nothing else.
Duplication may be the root of all evil in software.
if you keep your functions small, then the occasional multiple return, break, or continue statement does no harm and can sometimes even be more expressive than the single-entry, single-exit rule.
Comments are not like Schindler’s List. They are not “pure good.” Indeed, comments are, at best, a necessary evil.
Source code control systems are very good at remembering who added what, when. There is no need to pollute the code with little bylines.
HTML in source code comments is an abomination, as you can tell by reading the code below. It makes the comments hard to read in the one place where they should be easy to read—the editor/IDE.
you must write a comment, then make sure it describes the code it appears near. Don’t
Don’t put interesting historical discussions or irrelevant descriptions of details into your comments.
The connection between a comment and the code it describes should be obvious.
The functionality that you create today has a good chance of changing in the next release, but the readability of your code will have a profound effect on all the changes that will ever be made.
Small files are usually easier to understand than large files are.
If one function calls another, they should be vertically close, and the caller should be above the callee, if at all possible.
In general we want function call dependencies to point in the downward direction. That is, a function that is called should be below a function that does the calling.2
This suggests that we should strive to keep our lines short. The old Hollerith limit of 80 is a bit arbitrary, and I’m not opposed to lines edging out to 100 or even 120. But beyond that is probably just careless.
We use horizontal white space to associate things that are strongly related and disassociate things that are more weakly related.
Another use for white space is to accentuate the precedence of operators.
The factors have no white space between them because they are high precedence. The terms are separated by white space because addition and subtraction are lower precedence.
If I have long lists that need to be aligned, the problem is the length of the lists, not the lack of alignment.
A team of developers should agree upon a single formatting style, and then every member of that team should use that style.
We do not want to expose the details of our data. Rather we want to express our data in abstract terms.
Objects hide their data behind abstractions and expose functions that operate on that data. Data structure expose their data and have no meaningful functions.
Procedural code (code using data structures) makes it easy to add new functions without changing the existing data structures. OO code, on the other hand, makes it easy to add new classes without changing existing functions.
Procedural code makes it hard to add new data structures because all the functions must change. OO code makes it hard to add new functions because all the classes must change.
Mature programmers know that the idea that everything is an object is a myth. Sometimes you really do want simple data structures with procedures operating on them.
There is a well-known heuristic called the Law of Demeter2 that says a module should not know about the innards of the objects it manipulates.
The method should not invoke methods on objects that are returned by any of the allowed functions. In other words, talk to friends, not to strangers.