More on this book
Community
Kindle Notes & Highlights
Read between
April 20 - July 17, 2019
High class and method counts are sometimes the result of pointless dogmatism.
Concurrency is a decoupling strategy. It helps us decouple what gets done from when it gets done.
Recommendation: Keep your concurrency-related code separate from other code.6
Recommendation: Take data encapsulation to heart; severely limit the access of any data that may be shared.
Recommendation: Attempt to partition data into independent subsets than can be operated on by independent threads, possibly in different processors.
Recommendation: Think about shut-down early and get it working early. It’s going to take longer than you expect. Review existing algorithms because this is probably harder than you think.
Recommendation: Write tests that have the potential to expose problems and then run them frequently, with different programatic configurations and system configurations and load. If tests ever fail, track down the failure. Don’t ignore a failure just because the tests pass on a subsequent run.
Most developers do not have an intuitive feel for how threading interacts with other code (authors included).
Recommendation: Do not ignore system failures as one-offs.
Multithreaded code behaves differently in different environments.
Recommendation: Use jiggling strategies to ferret out errors.
If we have learned anything over the last couple of decades, it is that programming is a craft more than it is a science.
To write clean code, you must first write dirty code and then clean it.
One of the best ways to ruin a program is to make massive changes to its structure in the name of improvement.
I use the discipline of Test-Driven Development (TDD). One of the central doctrines of this approach is to keep the system running at all times.
Much of good software design is simply about partitioning—creating appropriate places to put different kinds of code.
Commented-out code is an abomination.
Every boundary condition, every corner case, every quirk and exception represents something that can confound an elegant and intuitive algorithm. Don’t rely on your intuition. Look for every boundary condition and write a test for it.
Turning off failing tests and telling yourself you’ll get them to pass later is as bad as pretending your credit cards are free money.
Every time you see duplication in the code, it represents a missed opportunity for abstraction.
We don’t want lower and higher level concepts mixed together.
In general, base classes should know nothing about their derivatives.
Good software developers learn to limit what they expose at the interfaces of their classes and modules.
Hide your data. Hide your utility functions. Hide your constants and your temporaries.
The problem with dead code is that after awhile it starts to smell.
When you find dead code, do the right thing. Give it a decent burial. Delete it from the system.
If you do something a certain way, do all similar things in the same way.
In general an artificial coupling is a coupling between two modules that serves no direct purpose. It is a result of putting a variable, constant, or function in a temporarily convenient, though inappropriate, location. This is lazy and careless.
When a method uses accessors and mutators of some other object to manipulate the data within that object, then it envies the scope of the class of that other object.
All else being equal, we want to eliminate Feature Envy because it exposes the internals of one class to another.
In general it is better to have many functions than to pass some code into a function to select the behavior.
Code should be placed where a reader would naturally expect it to be.
It is remarkable how an opaque module can suddenly become transparent simply by breaking the calculations up into well-named intermediate values.
If you have to look at the implementation (or documentation) of the function to know what it does, then you should work to find a better name or rearrange the functionality so that it can be placed in functions with better names.
In general it is a bad idea to have raw numbers in your code. You should hide them behind well-named constants.
Ambiguities and imprecision in code are either a result of disagreements or laziness. In either case they should be eliminated.
Extract functions that explain the intent of the conditional.
Separating levels of abstraction is one of the most important functions of refactoring, and it’s one of the hardest to do well.
it comes down to making sure that modules know only about their immediate collaborators and do not know the navigation map of the whole system.
Don’t use inheritance as a way to cheat the scoping rules of the language. Use a static import instead.
Names in software are 90 percent of what make software readable.
Don’t pick names that communicate implementation; choose names the reflect the level of abstraction of the class or function you are working in.
the longer the scope of the name, the longer and more precise the name should be.
Keep your names free of Hungarian pollution.
A test suite should test everything that could possibly break.
T2: Use a Coverage Tool!
T3: Don’t Skip Trivial Tests
Take special care to test boundary conditions.
Complete test cases, ordered in a reasonable way, expose patterns.
So do what you must to keep your tests fast.

