├── README.md
├── comments.md
├── formatting.md
├── functions.md
├── naming.md
└── objects-and-data-structures.md
/README.md:
--------------------------------------------------------------------------------
1 | # clean-code
2 |
3 | In this repo you can find my notes for [Clean Code](http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882/ref=sr_1_1?ie=UTF8&qid=1452837629&sr=8-1&keywords=clean+code) as I read through it. This is primarily to act as a learning tool and reference for me but I hope others will find it beneficial as well. Other repos that were trying to do this were not organized well and had either too much or too little information. Here I will list the handfull of notes I think most important for each section.
4 |
5 |
6 | ## Sections
7 |
8 | * [`Naming`](#naming)
9 | * [`Functions`](#functions)
10 | * [`Comments`](#comments)
11 | * [`Formatting`](#formatting)
12 | * [`Objects vs. Data Structures`](#objects-and-data-structures)
13 | * [`Error Handling`](#error-handling)
14 |
15 |
16 | ### Naming
17 | - Change names when you find better ones
18 | - A name should tell you why something exists, what it does, and how it is used
19 | - The length of a name should correspond to the size of its scope
20 | - Pick one word per abstract concept and stick with it *(ex. `get`, `retrieve`, `fetch` are all equivalent so pick one)*
21 | - The author is responsible for making his code clear
22 | - Add prefixes as a last resort
23 | - [View More](/naming.md)
24 |
25 |
26 |
27 | ### Functions
28 | - Keep very small (hopefully < ~10 lines)
29 | - Do a single thing
30 | - The "thing" a function is doing should include steps *one level of abstraction below* the name of the function
31 | - Code should read like a top-down narrative. Each level of abstraction leads to the next.
32 | - Long and descriptive function names are acceptable
33 | - Keep function arguments between 0 and 3
34 | - Keep functions pure (no side-effects!)
35 | - Functions should *either do something or answer something, but not both*.
36 | - Don't repeat yourself
37 | - [View More](/functions.md)
38 |
39 |
40 | ### Comments
41 | - Comments are for compensating for our lack of ability to express ourselves in code
42 | - Comments are hard to maintain, think hard before you add some
43 | - *Inaccurate comments are far worse than no comments*
44 | - *Don't leave commented out code.* Others will be confused and afraid to remove it.
45 | - Connection between the code and it's comment should be obvious
46 | - *Comments shouldn't need their own explanation*
47 | - A good function name is usually better than a comment header
48 | - [View More](/comments.md)
49 |
50 |
51 | ### Formatting
52 | - Stick to a common set of style rules
53 | - **Style and discipline survives even if your code doesn't**
54 | - Try and keep files between 200 and 500 lines
55 | - **Vertical Formatting** - High to low-level, separate groups of related lines by a blank line, tightly-related code should be vertically dense
56 | - Caller functions should be above their callees (ideally). *This gives the program a natural flow.*
57 | - Low-level functions should come last
58 | - Keep lines short (~120 characters)
59 | - Use horizontal whitespace to associate strongly related things
60 | - [View More](/formatting.md)
61 |
62 |
63 | ### Objects vs. Data Structures
64 | - Hiding implementation is about abstraction
65 | - Abstraction allows manipulatin of the *essence* of the data, without having to know it's implementation
66 | - Seriously think about best way to represent the data an object contains
67 | - **Objects** hide their data behind abstractions and expose functions that operate on that data
68 | - **Data Structures** expose their data and have no meanigful functions
69 | - "A module should not know about the innard of the objects it manipulates" - (Law of Demeter)
70 | - Example of a "Train Wreck" `String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();`
71 | - [View More](/objects-and-data-structures.md)
72 |
73 |
74 | ### Error Handling
75 | - Keep error handling separate from logic
76 | - Throw exceptions vs. returning error codes
77 | - Stack traces can't tell you the intent of the failed operation
78 | - Pass helpful error messages with your exceptions
79 | - Wrap 3rd-party APIs - makes it easier to switch and aren't tied to a vendor's API choices
80 | - The Special Case Pattern
81 | - Don't return or pass `null`
82 | - **Treat error handling as a separate concern!**
83 |
--------------------------------------------------------------------------------
/comments.md:
--------------------------------------------------------------------------------
1 | # Comments
2 | - Comments are for compensating for our lack of ability to express ourselves in code
3 | - Comments are hard to maintain, think hard before you add some
4 | - **Inaccurate comments are far worse than no comments**. Set expectations that will never be filled, lay down rules that need not and should not be followed.
5 | - Write a function that describes the same thing that a would-be comment would
6 | - There are a few types of acceptable comments
7 | - **Legal Comments** - Copyright, author statements
8 | - **Informative Comments** - Provide basic information or context to make something easier to understand
9 | - **Explanation of Intent** - Used for explaining a decision
10 | - **Clarification** - Useful for clarifying obscure concepts; good for use with standard libraries or code you can't modify
11 | - **Warning of Consequences** - Warn a future engineer about something
12 | - **TODO Comments** - Useful for marking something that should be done but that you may not have time to finish now. NOT an excuse to leave bad code.
13 | - **Amplification** - Used to amplify the importance of something that may otherwise seem inconsequential
14 | - Bad types of comments include mumbling, redundant, misleading, mandated, journal, and noise comments
15 | - It's silly to mandate that every function have a documenting comment. Not only will this clutter your code but it is just another thing to keep updated.
16 | - **Don't leave commented out code.** Others will be confused and afraid to remove it.
17 | - Only include local information in your comments. You can't depend on global information staying the same.
18 | - Connection between the code and it's comment should be obvious
19 | - **Comments shouldn't need their own explanation**
20 | - A good function name is usually better than a comment header
21 | - Generated documentation for internal functions is generally not useful
22 | - Comments can be used to ease a reader into a complicated routine
--------------------------------------------------------------------------------
/formatting.md:
--------------------------------------------------------------------------------
1 | # Formatting
2 | - Stick to a common set of style rules
3 | - **Getting it to work isn't the first concern!** Code style and readability will affect the code long after the original has been changed.
4 | - **Style and discipline survives even if your code doesn't**
5 | - Try and keep files between 200 and 500 lines
6 | - **Vertical Formatting** - High to low-level, separate groups of related lines by a blank line, tightly-related code should be vertically dense
7 | - Concepts closely related should be kept vertically close
8 | - Vertical distance between concepts should be a measure of how important each is to understanding the other
9 | - Declare variables as close to their usage as possible
10 | - Short functions should have all variables declared at top
11 | - Declare instance variables at the top of classes
12 | - Caller functions should be above their callees (ideally). *This gives the program a natural flow.*
13 | - Low-level functions should come last
14 | - Keep lines short (~120 characters)
15 | - Use horizontal whitespace to associate strongly related things
16 |
--------------------------------------------------------------------------------
/functions.md:
--------------------------------------------------------------------------------
1 | # Functions
2 | - **Keep very small (hopefully < ~10 lines)**
3 | - A function should lead you to the next function in a compelling order
4 | - Extract conditionals to functions (ex. `isLoading()`). This increases readability and helps keep functions small
5 | - **Do a single thing**
6 | - The "thing" a function is doing should include steps *one level of abstraction below* the name of the function
7 | - Statements within a function should be on the same level of abstraction. For example, `getUser` and `parseInt(45)` are not on the same levels of abstraction. Using different levels of abstraction in a single function creates confusion for the reader. Is a particular expression an essential concept or a detail? It's hard to know when mixing levels of abstraction.
8 | - Code should read like a top-down narrative. Each level of abstraction leads to the next.
9 | - Switch statements should be buried in a low-level class and not repeated.
10 | - Long and descriptive function names are acceptable
11 | - Choosing function names may take time. **Don't be afraid to try multiple names** (find and replace is trivial).
12 | - **Keep function arguments between 0 and 3**
13 | - Think hard about using three arguments.
14 | - **Keep functions pure (no side-effects!)**
15 | - Don't use flag arguments. This immediately indicates that the function is doing more than one thing. You should split the function up instead.
16 | - Reduce the number of arguments by creating objects instead (ex. `makeCircle(Point: center, int: radius)`)
17 | - Be careful of dyads (2 arguments). Many arguments don't have a natural ordering and can easily cause confusion as to which comes first (ex. `assertEqual(expected, actual)`).
18 | - Arguments are inputs to functions, don't manipulate them
19 | - Functions should **either do something or answer something, but not both**.
20 | - Prefer exceptions over returning error codes. Returning error codes forces the developer to handle that code immediately (ex. `if (deleteUser() === OK)` and mixes command and query. Exceptions allow error handling to be separated cleanly from the "happy path".
21 | - **Don't repeat yourself**
22 | - No one starts by writing a perfect function. Usually the first version is a long mess that takes effort to cleanup and break into separate components - just like writing.
23 | - Systems are stories to be told rather than programs to be written.
--------------------------------------------------------------------------------
/naming.md:
--------------------------------------------------------------------------------
1 | # Naming
2 |
3 | - Change names when you find better ones
4 | - A name should tell you why something exists, what it does, and how it is used
5 | - Avoid disinformation *(ex. don't name something `personList` if it is not a `List`)*
6 | - Avoid similarly shaped names for dissimilar concepts
7 | - Don't name things to satisfy a compiler or interpreter (if possible)
8 | - Avoid meaningless distinctions *(ex. `ProductInfo` vs `ProductData` both mean the same thing but look different)*
9 | - Use pronounceable names
10 | - **The length of a name should correspond to the size of its scope**
11 | - Avoid mental mapping
12 | - Methods should have verb names *(ex. `createPayment()`)*
13 | - Accessors, mutators, and predicates should be prefixed with `get`, `set`, and `is`
14 | - Don't be cute (i.e don't use slang or colloquialisms)
15 | - *Pick one word per abstract concept and stick with it *(ex. `get`, `retrieve`, `fetch` are all equivalent so pick one)*
16 | - Consistent lexicon == good
17 | - The author is responsible for making his code clear
18 | - Prefer drawing names from the solution domain (i.e Computer Science). This way developers don't have to be domain experts to know what something means.
19 | - When there is no technical (i.e solution domain) term for something, borrow from the problem domain. Code that has more to do with the problem domain should have names drawn from there anyways.
20 | - Few names are meaningful in and of themselves - make sure you place names in context by enclosing them in well-named classes, functions, or namespaces
21 | - *Add prefixes as a last resort*
22 | - Shorter names are generally better than longer ones - add no more context to a name than is necessary
23 | - Choosing good names requires good descriptive skills and a shared cultural background
24 |
--------------------------------------------------------------------------------
/objects-and-data-structures.md:
--------------------------------------------------------------------------------
1 | # Objects vs. Data Structures
2 | - Hiding implementation is about abstraction
3 | - Abstraction allows manipulatin of the *essence* of the data, without having to know it's implementation
4 | - Seriously think about best way to represent the data an object contains
5 | - Don't blindly add getters and setters
6 | - **Objects** hide their data behind abstractions and expose functions that operate on that data
7 | - **Data Structures** expose their data and have no meanigful functions
8 | - "A module should not know about the innard of the objects it manipulates" - (Law of Demeter)
9 | - Example of a "Train Wreck" `String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();`
10 | - Law of Demeter doesn't apply to Data Structures who naturally expose their internal structure
11 | - Hybrid structures that are half object and half data structure are the worst of both worlds. They have functions that do significant things but also public variables or getters that tempt external functions to use those variables the way a procedural would use a data structure.
12 | - Getters and setters directly linked to private variables have little value (ex. `getAge()` when `age` is a private)
13 | - Objects expose behavior and hide their data. Easy to add new kinds of objects without changing behaviors. Hard to add new behaviors without changing objects.
14 | - Data Structures expose data and have no significant behavior. Easy to add new behaviors to existing data structures. Hard to add new data structures to existing functions.
15 | - Sometimes we want flexibility to add new data types. Othertimes we want flexibility to add new behaviors.
16 | - Choose the right approach for each problem
--------------------------------------------------------------------------------