Five Lines of Code

Book description

In Five Lines of Code you will learn:

  • The signs of bad code
  • Improving code safely, even when you don’t understand it
  • Balancing optimization and code generality
  • Proper compiler practices
  • The Extract method, Introducing Strategy pattern, and many other refactoring patterns
  • Writing stable code that enables change-by-addition
  • Writing code that needs no comments
  • Real-world practices for great refactoring

Improving existing code—refactoring—is one of the most common tasks you’ll face as a programmer. Five Lines of Code teaches you clear and actionable refactoring rules that you can apply without relying on intuitive judgements such as “code smells.” Following the author’s expert perspective—that refactoring and code smells can be learned by following a concrete set of principles—you’ll learn when to refactor your code, what patterns to apply to what problem, and the code characteristics that indicate it’s time for a rework.

About the Technology
Every codebase includes mistakes and inefficiencies that you need to find and fix. Refactor the right way, and your code becomes elegant, easy to read, and easy to maintain. In this book, you’ll learn a unique approach to refactoring that implements any method in five lines or fewer. You’ll also discover a secret most senior devs know: sometimes it’s quicker to hammer out code and fix it later!

About the Book
Five Lines of Code is a fresh look at refactoring for developers of all skill levels. In it, you’ll master author Christian Clausen’s innovative approach, learning concrete rules to get any method down to five lines—or less! You’ll learn when to refactor, specific refactoring patterns that apply to most common problems, and characteristics of code that should be deleted altogether.

What's Inside
  • The signs of bad code
  • Improving code safely, even when you don’t understand it
  • Balancing optimization and code generality
  • Proper compiler practices


About the Reader
For developers of all skill levels. Examples use easy-to-read Typescript, in the same style as Java and C#.

About the Author
Christian Clausen works as a Technical Agile Coach, teaching teams how to refactor code.

Quotes
Down to earth, focused, and right on point. It will challenge you without intimidating you and without insulting your intelligence.
- Robert C. Martin

A delightful and fun introduction to one of the most overlooked parts of programming—refactoring.
- Charles Lam, EVN AG

Gave me new insights on how to keep my code readable and maintainable. I highly recommend it.
- John Norcott, Webstaurantstore

These techniques are simple but powerful, and the exercises makes it easy to learn them. They can be used in any language I know!
- Christian Hasselbalch Thoudahl, BEC Financial Technologies

Publisher resources

View/Submit Errata

Table of contents

  1. inside front cover
    1. Quick overview of refactoring patterns
  2. Five Lines of Code
  3. Copyright
  4. dedication
  5. brief contents
  6. contents
  7. front matter
    1. foreword
    2. preface
      1. Goal: The selected rules and refactoring patterns
      2. Audience and roadmap
      3. About the teaching
      4. About the code
      5. liveBook discussion forum
      6. Bonus project
    3. acknowledgments
    4. about the author
    5. about the cover illustration
  8. 1 Refactoring refactoring
    1. 1.1 What is refactoring?
    2. 1.2 Skills: What to refactor?
      1. 1.2.1 An example code smell
      2. 1.2.2 An example rule
    3. 1.3 Culture: When to refactor?
      1. 1.3.1 Refactoring in a legacy system
      2. 1.3.2 When should you not refactor?
    4. 1.4 Tools: How to refactor (safely)
    5. 1.5 Tools you need to get started
      1. 1.5.1 Programming language: TypeScript
      2. 1.5.2 Editor: Visual Studio Code
      3. 1.5.3 Version control: Git
    6. 1.6 Overarching example: A 2D puzzle game
      1. 1.6.1 Practice makes perfect: A second codebase
    7. 1.7 A note on real-world software
    8. Summary
  9. 2 Looking under the hood of refactoring
    1. 2.1 Improving readability and maintainability
      1. 2.1.1 Making code better
      2. 2.1.2 Maintaining code . . . without changing what it does
    2. 2.2 Gaining speed, flexibility, and stability
      1. 2.2.1 Favoring composition over inheritance
      2. 2.2.2 Changing code by addition rather than modification
    3. 2.3 Refactoring and your daily work
      1. 2.3.1 Refactoring as a method for learning
    4. 2.4 Defining the “domain” in a software context
    5. Summary
  10. Part 1. Learn by refactoring a computer game
  11. 3 Shatter long functions
    1. 3.1 Establishing our first rule: Why five lines?
      1. 3.1.1 Rule: Five lines
    2. 3.2 Introducing a refactoring pattern to break up functions
      1. 3.2.1 Refactoring pattern: Extract method
    3. 3.3 Breaking up functions to balancing abstraction
      1. 3.3.1 Rule: Either call or pass
      2. 3.3.2 Applying the rule
    4. 3.4 Properties of a good function name
    5. 3.5 Breaking up functions that are doing too much
      1. 3.5.1 Rule: if only at the start
      2. 3.5.2 Applying the rule
    6. Summary
  12. 4 Make type codes work
    1. 4.1 Refactoring a simple if statement
      1. 4.1.1 Rule: Never use if with else
      2. 4.1.2 Applying the rule
      3. 4.1.3 Refactoring pattern: Replace type code with classes
      4. 4.1.4 Pushing code into classes
      5. 4.1.5 Refactoring pattern: Push code into classes
      6. 4.1.6 Inlining a superfluous method
      7. 4.1.7 Refactoring pattern: Inline method
    2. 4.2 Refactoring a large if statement
      1. 4.2.1 Removing generality
      2. 4.2.2 Refactoring pattern: Specialize method
      3. 4.2.3 The only switch allowed
      4. 4.2.4 Rule: Never use switch
      5. 4.2.5 Eliminating the if
    3. 4.3 Addressing code duplication
      1. 4.3.1 Couldn’t we use an abstract class instead of the interface?
      2. 4.3.2 Rule: Only inherit from interfaces
      3. 4.3.3 What is up with all this code duplication?
    4. 4.4 Refactoring a pair of complex if statements
    5. 4.5 Removing dead code
      1. 4.5.1 Refactoring pattern: Try delete then compile
    6. Summary
  13. 5 Fuse similar code together
    1. 5.1 Unifying similar classes
      1. 5.1.1 Refactoring pattern: Unify similar classes
    2. 5.2 Unifying simple conditions
      1. 5.2.1 Refactoring pattern: Combine ifs
    3. 5.3 Unifying complex conditions
      1. 5.3.1 Using arithmetic rules for conditions
      2. 5.3.2 Rule: Use pure conditions
      3. 5.3.3 Applying condition arithmetic
    4. 5.4 Unifying code across classes
      1. 5.4.1 Introducing UML class diagrams to depict class relations
      2. 5.4.2 Refactoring pattern: Introduce strategy pattern
      3. 5.4.3 Rule: No interface with only one implementation
      4. 5.4.4 Refactoring pattern: Extract interface from implementation
    5. 5.5 Unifying similar functions
    6. 5.6 Unifying similar code
    7. Summary
  14. 6 Defend the data
    1. 6.1 Encapsulating without getters
      1. 6.1.1 Rule: Do not use getters or setters
      2. 6.1.2 Applying the rule
      3. 6.1.3 Refactoring pattern: Eliminate getter or setter
      4. 6.1.4 Eliminating the final getter
    2. 6.2 Encapsulating simple data
      1. 6.2.1 Rule: Never have common affixes
      2. 6.2.2 Applying the rule
      3. 6.2.3 Refactoring pattern: Encapsulate data
    3. 6.3 Encapsulating complex data
    4. 6.4 Eliminating a sequence invariant
      1. 6.4.1 Refactoring pattern: Enforce sequence
    5. 6.5 Eliminating enums another way
      1. 6.5.1 Enumeration through private constructors
      2. 6.5.2 Remapping numbers to classes
    6. Summary
  15. Part 2. Taking what you have learned into the real world
  16. 7 Collaborate with the compiler
    1. 7.1 Getting to know the compiler
      1. 7.1.1 Weakness: The halting problem limits compile-time knowledge
      2. 7.1.2 Strength: Reachability ensures that methods return
      3. 7.1.3 Strength: Definite assignment prevents accessing uninitialized variables
      4. 7.1.4 Strength: Access control helps encapsulate data
      5. 7.1.5 Strength: Type checking proves properties
      6. 7.1.6 Weakness: Dereferencing null crashes our application
      7. 7.1.7 Weakness: Arithmetic errors cause overflows or crashes
      8. 7.1.8 Weakness: Out-of-bounds errors crash our application
      9. 7.1.9 Weakness: Infinite loops stall our application
      10. 7.1.10 Weakness: Deadlocks and race conditions cause unintended behavior
    2. 7.2 Using the compiler
      1. 7.2.1 Making the compiler work
      2. 7.2.2 Don’t fight the compiler
    3. 7.3 Trusting the compiler
      1. 7.3.1 Teach the compiler invariants
      2. 7.3.2 Pay attention to warnings
    4. 7.4 Trusting the compiler exclusively
    5. Summary
  17. 8 Stay away from comments
    1. 8.1 Deleting outdated comments
    2. 8.2 Deleting commented-out code
    3. 8.3 Deleting trivial comments
    4. 8.4 Transforming comments into method names
      1. 8.4.1 Using comments for planning
    5. 8.5 Keeping invariant-documenting comments
      1. 8.5.1 Invariants in the process
    6. Summary
  18. 9 Love deleting code
    1. 9.1 Deleting code may be the next frontier
    2. 9.2 Deleting code to get rid of incidental complexity
      1. 9.2.1 Technical ignorance from inexperience
      2. 9.2.2 Technical waste from time pressure
      3. 9.2.3 Technical debt from circumstances
      4. 9.2.4 Technical drag from growing
    3. 9.3 Categorizing code based on intimacy
    4. 9.4 Deleting code in a legacy system
      1. 9.4.1 Using the strangler fig pattern to get insight
      2. 9.4.2 Using the strangler fig pattern to improve the code
    5. 9.5 Deleting code from a frozen project
      1. 9.5.1 Making the desired outcome the default
      2. 9.5.2 Minimizing waste with spike and stabilize
    6. 9.6 Deleting branches in version control
      1. 9.6.1 Minimizing waste by enforcing a branch limit
    7. 9.7 Deleting code documentation
      1. 9.7.1 Algorithm to determine how to codify knowledge
    8. 9.8 Deleting testing code
      1. 9.8.1 Deleting optimistic tests
      2. 9.8.2 Deleting pessimistic tests
      3. 9.8.3 Fixing or deleting flaky tests
      4. 9.8.4 Refactoring the code to get rid of complicated tests
      5. 9.8.5 Specializing tests to speed them up
    9. 9.9 Deleting configuration code
      1. 9.9.1 Scoping configuration in time
    10. 9.10 Deleting code to get rid of libraries
      1. 9.10.1 Limiting our reliance on external libraries
    11. 9.11 Deleting code from working features
    12. Summary
  19. 10 Never be afraid to add code
    1. 10.1 Accepting uncertainty: Enter the danger
    2. 10.2 Using spikes to overcome the fear of building the wrong thing
    3. 10.3 Overcoming the fear of waste or risk with a fixed ratio
    4. 10.4 Overcoming the fear of imperfection by embracing gradual improvement
    5. 10.5 How copy and paste effects change velocity
    6. 10.6 Modification by addition through extensibility
    7. 10.7 Modification by addition enables backward compatibility
    8. 10.8 Modification by addition through feature toggles
    9. 10.9 Modification by addition through branch by abstraction
    10. Summary
  20. 11 Follow the structure in the code
    1. 11.1 Categorizing structure based on scope and origin
    2. 11.2 Three ways that code mirrors behavior
      1. 11.2.1 Expressing behavior in the control flow
      2. 11.2.2 Expressing behavior in the structure of the data
      3. 11.2.3 Expressing behavior in the data
    3. 11.3 Adding code to expose structure
    4. 11.4 Observing instead of predicting, and using empirical techniques
    5. 11.5 Gaining safety without understanding the code
      1. 11.5.1 Gaining safety through testing
      2. 11.5.2 Gaining safety through mastery
      3. 11.5.3 Gaining safety through tool assistance
      4. 11.5.4 Gaining safety through formal verification
      5. 11.5.5 Gaining safety through fault tolerance
    6. 11.6 Identifying unexploited structures
      1. 11.6.1 Exploiting whitespace with extraction and encapsulation
      2. 11.6.2 Exploiting duplication with unification
      3. 11.6.3 Exploiting common affixes with encapsulation
      4. 11.6.4 Exploiting the runtime type with dynamic dispatch
    7. Summary
  21. 12 Avoid optimizations and generality
    1. 12.1 Striving for simplicity
    2. 12.2 When and how to generalize
      1. 12.2.1 Building minimally to avoid generality
      2. 12.2.2 Unifying things of similar stability
      3. 12.2.3 Eliminating unnecessary generality
    3. 12.3 When and how to optimize
      1. 12.3.1 Refactoring before optimizing
      2. 12.3.2 Optimizing according to the theory of constraints
      3. 12.3.3 Guiding optimization with metrics
      4. 12.3.4 Choosing good algorithms and data structures
      5. 12.3.5 Using caching
      6. 12.3.6 Isolating optimized code
    4. Summary
  22. 13 Make bad code look bad
    1. 13.1 Signaling process issues with bad code
    2. 13.2 Segregating into pristine and legacy code
      1. 13.2.1 The broken window theory
    3. 13.3 Approaches to defining bad code
      1. 13.3.1 The rules in this book: Simple and concrete
      2. 13.3.2 Code smells: Complete and abstract
      3. 13.3.3 Cyclomatic complexity: Algorithmic (objective)
      4. 13.3.4 Cognitive complexity: Algorithmic (subjective)
    4. 13.4 Rules for safely vandalizing code
    5. 13.5 Methods for safely vandalizing code
      1. 13.5.1 Using enums
      2. 13.5.2 Using ints and strings as type codes
      3. 13.5.3 Putting magic numbers in the code
      4. 13.5.4 Adding comments to the code
      5. 13.5.5 Putting whitespace in the code
      6. 13.5.6 Grouping things based on naming
      7. 13.5.7 Adding context to names
      8. 13.5.8 Creating long methods
      9. 13.5.9 Giving methods many parameters
      10. 13.5.10 Using getters and setters
    6. Summary
  23. 14 Wrapping up
    1. 14.1 Reflecting on the journey of this book
      1. 14.1.1 Introduction: Motivation
      2. 14.1.2 Part 1: Making it concrete
      3. 14.1.3 Part 2: Widening the horizon
    2. 14.2 Exploring the underlying philosophy
      1. 14.2.1 Searching for ever-smaller steps
      2. 14.2.2 Searching for the underlying structure
      3. 14.2.3 Using the rules for collaboration
      4. 14.2.4 Prioritizing the team over individuals
      5. 14.2.5 Prioritize simplicity over completeness
      6. 14.2.6 Using objects or higher-order functions
    3. 14.3 Where to go from here
      1. 14.3.1 Micro-architecture route
      2. 14.3.2 Macro-architecture route
      3. 14.3.3 Software quality route
    4. Summary
  24. Appendix A. Installing the tools for part 1
    1. Node.js
    2. TypeScript
    3. Visual Studio Code
    4. Git
    5. Setting up the TypeScript project
    6. Building the TypeScript project
    7. How to modify the level
  25. index
  26. inside back cover
    1. Quick overview of rules

Product information

  • Title: Five Lines of Code
  • Author(s): Christian Clausen
  • Release date: October 2021
  • Publisher(s): Manning Publications
  • ISBN: 9781617298318