├── 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 --------------------------------------------------------------------------------