Clean Code by Robert C. Martin
I recommend buying and reading this book more than once. This is a summary of what is included:
[ PART I ]
Chapter 1: Authors
I am an author, writing for readers who will judge your effort.
How to clean up the code? Leave the campground cleaner than you found it.!
Chapter 2: Meaningful Names
Names should reveal intent - take care when choosing your names and change them when you find better ones. Can’t do that with a kid.
Magic Numbers - Unique values with unexplained meaning or multiple occurrences which could (preferably) be replaced with named constants.
Avoid Disinformation - keep in mind that certain names may cause confusion or have a different meaning for different people.
Make Meaningful distinctions - different variable or methods names with a clear difference of what they are or do.
User pronounceable Names - just because.
Use searchable names - length of a name should correspond to the size of its scope.
Avoid Encodings -
Avoid mental mapping
Class Names - noun or noun phrase names
Method Names - verb or verb phrase names
Overloaded constructors
Pick one word per concept: get, fetch, retrieve
Don’t pun: avoid using one term for different purposes.
Use solution domain names
Add meaningful context
Shorter names are “generally” better than longer ones
Chapter 3: Methods
Small - less than 20 lines long. :)
Blocks and Indenting - (if, else, while) should be one line long and that line be a method call.
Do 1 thing - methods should do one thing and do it well. Can you extract another method from it with a different name? Methods that do 1 thing cannot be divided into sections. Avoid coupling.
One level of abstraction per method
Step down Rule - code should read like a top down narrative, descending levels of abstraction.
Switch Statements - avoid them and if can’t, use in an abstract factory (appear once, are used to create polymorphic objects, and hide behind an inheritance).
Use Descriptive Names - what is the 1 thing the method is doing? Name it properly.
Method Arguments - Ideal number of arguments is 0 and 3 or more should be avoided.
Monadic Methods: (1 parameter) verifies something or transforms something and if so, returns a value.
Avoid flag arguments: (passing a boolean as parameter)
Dyadic Methods: (2 parameters) avoid when possible, use 2 parameters that make sense together.
Triad Methods: avoid.
When a function seems to need more than 2 or 3 arguments, some of those arguments ought to be wrapped in a class of their own.
Choose smart verb noun pairs: ie. Write(name).
Avoid Output Arguments - If your function must change the state of something, have it change the state of its owning object.
Command Query Separation - a method doing something shouldn’t return a boolean. It causes confusion of whether it performs a query or a command.
Exceptions instead of returning error code
Don’t repeat yourself
Structured Programming - this applies for big methods
One return statement in a function
no break or continue in a loop
and never a goto statement
Chapter 4 : Comments
In summary, a comment is good if it describes a class or explains unique functionality of the class.
Chapter 5 : Formatting
Formatting for our codes to be clean and easy to communicate. Individuals/Teams should set a list of rules to follow through code.
Chapter 6 : Objects and Data Structures
Data Abstraction - Hiding implementation is not just a matter of putting a layer of functions between the variables but about abstractions.
Data/Object Anti-Symmetry - Objects hide their data behind abstractions and expose functions that operate on that data (getters and setters simply get the data).
Law of Demeter - a method m of class C should only call the methods of:
C
An object created by f or passed as argument to f
An object held in an instance variable of C
A method should not invoke methods on objects returned by the allowed function.
Train wreck code - avoid coupled code
final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
Treat DTOs as data structures and use other objects with the business rules.
Chapter 7 : Error Handling
Use exceptions rather than return codes
Write try-catch statement first - build the transaction scope of the try first and maintain the transaction nature of the scope.
Use unchecked exceptions - checked exceptions thrown at the lowest level result in a cascade of changes breaking encapsulation.
Oracle - If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception.
Provide context with the exception - message should contain the operation that failed and the type of failure.
Define exception classes in terms of the caller’s needs - if multiple exceptions are thrown and the catch is the same for all:
Define the normal flow -
Don’t return null and don’t pass null
Chapter 8 : Boundaries
Integrating foreign code with ours. Practices and techniques to keep the boundaries of our software clean.
Map ie.:
Sensor s = (Sensor)sensors.get(sensorId ); //Casting and not as readable
...
Map<Sensor> sensors = new HashMap<Sensor>();
Sensor s = sensors.get(sensorId ); //Readability improved, yet too flexible
…
public class Sensors {
private Map sensors = new HashMap();
public Sensor getById(String id) {
return (Sensor) sensors.get(id);
}
} // The class manages the casting and type of the Sensors object and the use of the Map class is restricted by the class.
Chapter 9 : Unit Tests
Test code is as important as production code. It keeps our code flexible and allows us to make changes without worries.
Clean Tests - are readable
Build-Operate-Check pattern
Domain specific test language - Build your own testing API
One Assert per Test (easier to understand - but not the best option always)
Single Concept per Test
FIRST - Fast, Independent, Repeatable, Self-validating, Timely
Chapter 10 : Classes
Class Organization - Variables first - public static constants, private static variables, private instance variables, public functions, private utilities under function used in.
Encapsulation - variables and utility functions private, unless needed by a test.
Classes should be small - count responsibilities.
Single Responsibility Principle (SRP) - a class should have one reason to change.
Cohesion - methods in a class should manipulate 1 or 2 class fields.
Open-Closed Principle (OCP) - classes should be open for extension but closed for modification (organize our classes in a way that change doesn’t affect them).
Dependency Inversion Principle (DIP) - our classes should depend on abstraction, not concrete details (Isolating from change).
Chapter 11 : Systems
Chapter 12 : Emergence
Four Rules of Simple Design: A design is “simple” if
Rule 1: Runs all tests - tests are a way to verify that a system runs at intended.
Simple Design Rules 2-4: Refactoring
Rule 2: No Duplication -
Rule 3: Expressive -
Choose good names (name show class responsibility)
Keep functions and classes small
Use standard nomenclature (ie. Design Patterns)
Well written tests
CARE and TRY
Minimal classes and methods -
Chapter 13 : Concurrency
Concurrency defence Principles:
Single Responsibility Principle - single reason to change. Keep concurrency code separate from other code.
Limit the scope of data - encapsulation! limit access of data that might be shared.
Use copies of data - to avoid sharing.
Threads should be as independent as possible - each thread should be independent and not share data with other threads.
Know the thread Library/API you’re using - For java review java.util.concurrent, java.util.concurrent.atomic, java.util.concurrent.locks.
Know your execution model -
Bound Resources - Resources of a fixed size or number used in a concurrent environment.
Mutual Exclusion - Only one thread can access shared data or a shared resource at a time.
Starvation - One thread or a group of threads is prohibited from proceeding
for an excessively long time or forever.
Deadlock - Two or more threads waiting for each other to finish.
Livelock Threads - in lockstep, each trying to do work but finding another
“in the way.”
-
-
-
Dependencies between synchronized methods - avoid using more than one synchronized method in a class.
Keep your synchronized sections as small as possible.
Shut-down code - 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.
[ PART II ]
Stay tuned for Part II.
Chapter 14 : Successive Refinement
Chapter 15 : JUnit Internals
Chapter 16 : Refactoring SerialDate
Chapter 17 : Smells and Heuristics