More on this book
Community
Kindle Notes & Highlights
Read between
January 30 - February 4, 2021
Later equals never.
Leave the campground cleaner than you found it.5
Agile Software Development: Principles, Patterns, and Practices (PPP).
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.
FUNCTIONS SHOULD DO ONE THING. THEY SHOULD DO IT WELL. THEY SHOULD DO IT ONLY.
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.
Using an output argument instead of a return value for a transformation is confusing. If a function is going to transform its input argument, the transformation should appear as the return value.
In general output arguments should be avoided. If your function must change the state of something, have it change the state of its owning object.
Functions should either do something or answer something, but not both.
Objects hide their data behind abstractions and expose functions that operate on that data. Data structure expose their data and have no meaningful functions.
Try to write tests that force exceptions, and then add behavior to your handler to satisfy your tests. This will cause you to build the transaction scope of the try block first and will help you maintain the transaction nature of that scope.
Create informative error messages and pass them along with your exceptions. Mention the operation that failed and the type of failure. If you are logging in your application, pass along enough information to be able to log the error in your catch.
we are advising you not to pass Maps (or any other interface at a boundary) around your system.
Learning Tests Are Better Than Free
First Law You may not write production code until you have written a failing unit test. Second Law You may not write more of a unit test than is sufficient to fail, and not compiling is failing. Third Law You may not write more production code than is sufficient to pass the currently failing test.
Timely The tests need to be written in a timely fashion. Unit tests should be written just before the production code that makes them pass. If you write tests after the production code, then you may find the production code to be hard to test. You may decide that some production code is too hard to test. You may not design the production code to be testable.
The first rule of classes is that they should be small. The second rule of classes is that they should be smaller than that.
With functions we measured size by counting physical lines. With classes we use a different measure. We count responsibilities.1
If we cannot derive a concise name for a class, then it’s likely too large. The more ambiguous the class name, the more likely it has too many responsibilities. For example, class names including weasel words like Processor or Manager or Super often hint at unfortunate aggregation of responsibilities.
We should also be able to write a brief description of the class in about 25 words, without using the words “if,” “and,” “or,” or “but.”
“The SuperDashboard provides access to the component that last held the focus, and it also allows us to track the version and build numbers.” The first “and” is a hint that SuperDashboard has too many responsibilities.
Single Responsibility Principle (SRP)2 states that a class or module should have one, and only one, reason to change.
Do you want your tools organized into toolboxes with many small drawers each containing well-defined and well-labeled components? Or do you want a few drawers that you just toss everything into?
A class in which each variable is used by each method is maximally cohesive.
When classes lose cohesion, split them!
Private method behavior that applies only to a small subset of a class can be a useful heuristic for spotting potential areas for improvement.
Classes should be open for extension but closed for modification.
By minimizing coupling in this way, our classes adhere to another class design principle known as the Dependency Inversion Principle (DIP).5 In essence, the DIP says that our classes should depend upon abstractions, not on concrete details. 5. [PPP]. Instead of being dependent upon the implementation details of the TokyoStock-Exchange class, our Portfolio class is now dependent upon the StockExchange interface. The StockExchange interface represents the abstract concept of asking for the current price of a symbol.
Separate Constructing a System from Using It
Software systems should separate the startup process, when the application objects are constructed and the dependencies are “wired” together, from the runtime logic that takes over after startup.
The separation of concerns is one of the oldest and most important design techniques in our craft.
The flow of control is easy to follow. The main function builds the objects necessary for the system, then passes them to the application, which simply uses them.
Inversion of Control moves secondary responsibilities from an object to other objects that are dedicated to the purpose, thereby supporting the Single Responsibility Principle.
In the context of dependency management, an object should not take responsibility for instantiating dependencies itself. Instead, it should pass this responsibility to another “authoritative” mechanism, thereby inverting the control. Because setup is a global concern, this authoritative mechanism will usually be either the “main” routine or a special-purpose container.
convention over configuration
A primary goal of tests is to act as documentation by example.
“Objects are abstractions of processing. Threads are abstractions of schedule.”
Unless carefully designed, systems that compete in this way can experience deadlock, livelock, throughput, and efficiency degradation. Most concurrent problems you will likely encounter will be some variation of these three problems.
Run your threaded code on all target platforms early and often.
To write clean code, you must first write dirty code and then clean it.
“The Principle of Least Surprise,”2 any function or class should implement the behaviors that another programmer could reasonably expect.
Things that don’t depend upon each other should not be artificially coupled.
If one module depends upon another, that dependency should be physical, not just logical. The dependent module should not make assumptions (in other words, logical dependencies) about the module it depends upon. Rather it should explicitly ask that module for all the information it depends upon.
Prefer Polymorphism to If/Else or Switch/Case
(For example, we don’t want a.getB().getC().doSomething();.) This is sometimes called the Law of Demeter. The Pragmatic Programmers call it “Writing Shy Code.”
Nomenclature
Use a Coverage Tool!