Last active
May 7, 2026 18:19
-
-
Save 8ullyMaguire/69fd61be824934d560f25b60b95408ef to your computer and use it in GitHub Desktop.
Code Principles
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ## Core Philosophy | |
| 1. **Make complexity the #1 enemy** – Complexity makes code hard to understand or modify. Fight it continuously. | |
| 2. **Strategic over tactical programming** – Don’t just make working code; invest time in good design to reduce long‑term complexity. Avoid being a “tactical tornado”. | |
| 3. **Zero tolerance for complexity** – Complexity accumulates incrementally. Remove it aggressively, even from small changes. | |
| 4. **Design it twice** – Explore at least two radically different designs before choosing one. | |
| 5. **Obviousness is the goal** – Good design makes the system obvious to readers, not just to the author. | |
| 6. **It’s easier to see design problems in someone else’s code** – Use code reviews to gain that perspective. | |
| 7. **If you aren’t improving the design when changing code, you’re probably making it worse** – Always leave the design better than you found it (Boy Scout Rule). | |
| --- | |
| ## Module Design (Deep Modules & Information Hiding) | |
| 8. **Deep modules** – Favour modules with a simple interface and a complex implementation. Shallow modules (many tiny classes/methods) increase overall complexity. | |
| 9. **Hide information** – Each module should encapsulate secrets that are likely to change. | |
| 10. **Avoid temporal decomposition** – Don’t design modules based on the order of operations (first do A, then B). Instead group by required knowledge. | |
| 11. **Different layer, different abstraction** – Adjacent layers with similar abstractions are a red flag. Eliminate pass‑through methods and variables. | |
| 12. **Pull complexity downwards** – Make lower layers handle the hard parts so that higher layers have a simple interface. | |
| 13. **General‑purpose modules are deeper** – Design modules that are slightly general; the interface should support future reuse while the implementation fits current needs. | |
| 14. **Better together or better apart?** – Combine elements if they share information, are used together, overlap conceptually, or simplify the interface. Split if they are truly independent. | |
| 15. **Define errors out of existence** – Reduce exception complexity by designing APIs that eliminate exceptional cases, handle errors at low levels, or crash when appropriate. | |
| 16. **Prefer polymorphism to conditionals** (if/else, switch/case). | |
| 17. **Separate multi‑threading code** from business logic. | |
| 18. **Use dependency injection** to decouple modules. | |
| --- | |
| ## Comments & Documentation | |
| 19. **Comments are not optional** – “Self‑documenting code” is a myth. Good comments add precision and intuition that code cannot express. | |
| 20. **Comment first** – Write the comment before the implementation. It helps clarify the design (like TDD, but for documentation). | |
| 21. **Comments should describe non‑obvious things** – Document the interface (what callers need to know) and important implementation details. Avoid redundancy. | |
| 22. **If naming is hard, the design is likely wrong** – Unclear names indicate missing abstractions or poor separation of concerns. | |
| 23. **Comments belong in the code, not in commit logs** – Keep explanations where future developers will see them. | |
| 24. **Don’t comment out code** – Just remove it. Use version control for history. | |
| 25. **Use comments to explain intent, clarify logic, or warn of consequences.** | |
| --- | |
| ## Naming | |
| 26. **Choose descriptive and unambiguous names** – Make meaningful distinctions. | |
| 27. **Use pronounceable and searchable names** – Avoid single letters (except trivial loops). | |
| 28. **Replace magic numbers with named constants** – Never embed literal values. | |
| 29. **Avoid encodings** – No Hungarian notation or type prefixes. | |
| 30. **Be consistent across the codebase** – Same concept, same name. | |
| --- | |
| ## Functions / Methods | |
| 31. **Each method should do one thing and do it completely** – No partial or fragmented operations. | |
| 32. **Long methods are fine** – Provided the signature is simple, the method is cohesive, and the code is easy to read. Don’t split artificially. | |
| 33. **Use descriptive names** – A method’s name should explain its overall effect. | |
| 34. **Prefer fewer arguments** – Zero or one is best. Use objects to group related parameters. | |
| 35. **No side effects** – A function should do only what its name says. | |
| 36. **Don’t use flag arguments** – Instead split into two independent methods (e.g., `renderActive()` and `renderInactive()` instead of `render(active)`). | |
| 37. **Prefer non‑static methods** (for polymorphism and testability). | |
| 38. **Avoid logical dependency** – Don’t write methods that work correctly only because of something else in the same class (order dependencies). | |
| --- | |
| ## Code Structure & Formatting | |
| 39. **Separate concepts vertically** – Put related code in dense blocks, separate different ideas with blank lines. | |
| 40. **Declare variables close to their usage** – Not at the top of the function. | |
| 41. **Place dependent functions close together** – Caller above callee (downward direction). | |
| 42. **Keep lines short** (e.g., < 100 characters). | |
| 43. **Don’t use horizontal alignment** – It creates noisy diffs. | |
| 44. **Use indentation and white space to show association** – Group related code, separate weakly related parts. | |
| 45. **Keep configurable data at high levels** (not buried deep in code). | |
| 46. **Prevent over‑configurability** – Compute reasonable defaults automatically instead of adding configuration parameters. | |
| --- | |
| ## Objects & Data Structures | |
| 47. **Hide internal structure** – No public fields or exposed internals. | |
| 48. **Prefer data structures (simple aggregates) over hybrids** – A class should be either an object (behavior + hidden data) or a plain data structure (no behavior). | |
| 49. **Classes should be small** – One responsibility, a small number of instance variables. | |
| 50. **Base classes know nothing about their derivatives** – Prefer composition or abstraction. | |
| 51. **Better to have many explicit functions than to pass a flag/selector into one function** – That’s the “flag argument” rule again. | |
| 52. **Follow the Law of Demeter** – A class should know only its direct dependencies. | |
| --- | |
| ## Testing | |
| 53. **One logical assert per test** – Makes failures easier to interpret. | |
| 54. **Tests must be readable, fast, independent, and repeatable** – No shared state, no external dependencies. | |
| 55. **Beware: Test‑Driven Development can promote tactical programming** – If it leads to shallow modules and minimal comments, compensate with strategic thinking. | |
| --- | |
| ## Consistency & Conventions | |
| 56. **Follow standard conventions** – Language, framework, team norms. | |
| 57. **Don’t “improve” existing conventions without a strong reason** – Inconsistency increases cognitive load. | |
| 58. **Use explanatory variables** to clarify complex conditions. | |
| 59. **Encapsulate boundary conditions** – Put edge‑case processing in one place. | |
| 60. **Prefer dedicated value objects over primitive types** (e.g., `Temperature` instead of `double`). | |
| 61. **Avoid negative conditionals** (`if (!notFound)` → `if (found)`). | |
| --- | |
| ## Code Smells (Signs of Bad Design) | |
| 62. **Rigidity** – A small change causes a cascade of changes. | |
| 63. **Fragility** – A single change breaks many unrelated places. | |
| 64. **Immobility** – You cannot reuse a piece of code in another project without high risk/effort. | |
| 65. **Needless complexity** – Over‑engineering, premature optimization, over‑configurability. | |
| 66. **Needless repetition** – Duplication of logic or knowledge. | |
| 67. **Opacity** – The code is hard to read and understand. | |
| 68. **Change amplification** – A simple change requires many edits. | |
| 69. **Cognitive load** – Developers must learn too much to make a change. | |
| 70. **Unknown unknowns** – You don’t know what to change, or whether you’ve broken something. | |
| --- | |
| ## Design for Performance & Maintenance | |
| 71. **Simpler code tends to be faster** – Clean, obvious code often performs well. Optimize only after measuring. | |
| 72. **Design around the critical path** – Keep performance‑sensitive parts small and obvious. | |
| 73. **Always find the root cause** – Don’t just fix the symptom; eliminate the underlying design flaw. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment