The book also teaches you to solve the complex timing bugs that inevitably creep into asynchronous and multithreaded code. In ad­vanced sections of the book you learn how composable abstractions help avoid repeating code and open up new levels of expressivity.

Table of Contents

  1. Cover
  2. Title Page
  3. Copyright
  4. Foreword
  5. Preface
  6. Acknowledgments
  7. About This Book
  8. About the Author
  9. Chapter 1: Welcome to Grokking Simplicity
    1. What is Functional Programming?
    2. The Problems with the Definition for Practical Use
    3. The Definition of FP Confuses Managers
    4. We Treat Functional Programming as a Set of Skills and Concepts
    5. Distinguishing Actions, Calculations, and Data
    6. Functional Programmers Distinguish Code That Matters When You Call It
    7. Functional Programmers Distinguish Inert Data From Code That Does Work
    8. Functional Programmers See Actions, Calculations, and Data
    9. The Three Categories of Code in FP
    10. How Does Distinguishing Actions, Calculations, and Data Help Us?
    11. Why is this Book Different from Other FP Books?
    12. What is Functional Thinking?
    13. Ground Rules for Ideas and Skills in this Book
  10. Chapter 2: Functional Thinking in Action
    1. Welcome to Toni’s Pizza
    2. Part 1: Distinguishing Actions, Calculations, and Data
    3. Organizing Code by “Rate of Change”
    4. Part 2: First-Class Abstractions
    5. Timelines Visualize Distributed Systems
    6. Multiple Timelines Can Execute in Different Orderings
    7. Hard-won Lessons About Distributed Systems
    8. Cutting the Timeline: Making the Robots Wait for Each Other
    9. Positive Lessons Learned About Timelines
  11. Part 1: Actions, Calculations, and Data
    1. Chapter 3: Distinguishing Actions, Calculations, and Data
    2. Actions, Calculations, and Data
    3. Actions, Calculations, and Data Apply to Any Situation
    4. Lessons from Our Shopping Process
    5. Applying Functional Thinking to New Code
    6. Drawing the Coupon Email Process
    7. Implementing the Coupon Email Process
    8. Applying Functional Thinking to Existing Code
    9. Actions Spread Through Code
    10. Actions Can Take Many Forms
    11. Chapter 4: Extracting Calculations from Actions
    12. Welcome to MegaMart.com!
    13. Calculating free Shipping
    14. Calculating Tax
    15. We Need to Make It More Testable
    16. We need to Make It More Reusable
    17. Distinguishing Actions, Calculations, and Data
    18. Functions Have Inputs and Outputs
    19. Testing and Reuse Relate to Inputs and Outputs
    20. Extracting a Calculation from An Action
    21. Extracting Another Calculation from an Action
    22. Let’s See All of Our Code in One Place
    23. Chapter 5: Improving the Design of Actions
    24. Aligning Design with Business Requirements
    25. Aligning the Function with Business Requirements
    26. Principle: Minimize Implicit Inputs and Outputs
    27. Reducing Implicit Inputs and Outputs
    28. Giving the Code a Once-Over
    29. Categorizing Our Calculations
    30. Principle: Design Is About Pulling Things Apart
    31. Improving the Design by Pulling add_item() Apart
    32. Extracting a Copy-On-Write Pattern
    33. Using add_item()
    34. Categorizing Our Calculations
    35. Smaller Functions and More Calculations
    36. Chapter 6: Staying Immutable in a Mutable Language
    37. Can Immutability be Applied Everywhere?
    38. Categorizing Operations into Reads, Writes, or Both
    39. The Three Steps of the Copy-On-Write Discipline
    40. Converting a Write to a Read With Copy-On-Write
    41. Complete Diff from Mutating to Copy-On-Write
    42. These Copy-On-Write Operations are Generalizable
    43. JavaScript Arrays at a Glance
    44. What to do if an Operation is a Read and a Write
    45. Splitting a Function that does a Read and Write
    46. Returning Two Values from One Function
    47. Reads to Immutable Data Structures are Calculations
    48. Applications Have State That Changes Over Time
    49. Immutable Data Structures are Fast Enough
    50. Copy-On-Write Operations on Objects
    51. JavaScript Objects at a Glance
    52. Converting Nested Writes to Reads
    53. What Gets Copied?
    54. Visualizing Shallow Copies and Structural Sharing
    55. Chapter 7: Staying Immutable with Untrusted Code
    56. Immutability with Legacy Code
    57. Our Copy-On-Write Code has to Interact with Untrusted Code
    58. Defensive Copying Defends the Immutable Original
    59. Implementing Defensive Copies
    60. The Rules of Defensive Copying
    61. Wrapping Untrusted Code
    62. Defensive Copying You May Be Familiar With
    63. Copy-On-Write and Defensive Copying Compared
    64. Deep Copies are More Expensive Than Shallow Copies
    65. Implementing Deep Copy in JavaScript is Difficult
    66. A Dialogue Between Copy-On-Write and Defensive Copying
    67. Chapter 8: Stratified Design: Part 1
    68. What is Software Design?
    69. What is Stratified Design?
    70. Developing Our Design Sense
    71. Patterns of Stratified Design
    72. Pattern 1: Straightforward Implementations
    73. Three Different Zoom Levels
    74. Extracting the for Loop
    75. Pattern 1 Review: Straightforward Implementation
    76. Chapter 9: Stratified Design: Part 2
    77. Patterns of Stratified Design
    78. Pattern 2: Abstraction Barrier
    79. Abstraction Barriers Hide Implementations
    80. Ignoring Details is Symmetrical
    81. Swapping the Shopping Cart’s Data Structure
    82. Re-Implementing the Shopping Cart as an Object
    83. The Abstraction Barrier Lets Us Ignore Details
    84. When to Use (and When ‘Not’ to Use!) Abstraction Barriers
    85. Pattern 2 Review: Abstraction Barrier
    86. Our Code is More Straightforward
    87. Pattern 3: Minimal Interface
    88. Pattern 3 Review: Minimal Interface
    89. Pattern 4: Comfortable Layers
    90. Patterns of Stratified Design
    91. What Does the Graph Show Us About Our Code?
    92. Code at the Top of the Graph is Easier to Change
    93. Testing Code at the Bottom is More Important
    94. Code at the Bottom is More Reusable
    95. Summary: What the Graph Shows Us About Our Code
  12. Part 2: First-Class Abstractions
    1. Chapter 10: First-Class Functions: Part 1
    2. Marketing Still Needs to Coordinate with Dev
    3. Code Smell: Implicit Argument in Function Name
    4. Refactoring: Express Implicit Argument
    5. Recognize What Is and What Isn’t First-Class
    6. Will Field Names as Strings Lead to More Bugs?
    7. Will First-Class Fields Make the API Hard to Change?
    8. We Will Use a Lot of Objects and Arrays
    9. First-Class Functions Can Replace any Syntax
    10. For loop example: Eating and cleaning up
    11. Refactoring: Replace Body with Callback
    12. What is this Syntax?
    13. Why are we Wrapping the Code in a Function?
    14. Chapter 11: First-Class Functions: Part 2
    15. One Code Smell and Two Refactorings
    16. Refactoring Copy-On-Write
    17. Refactoring Copy-On-Write for Arrays
    18. Returning Functions from Functions
    19. Chapter 12: Functional Iteration
    20. One Code Smell and Two Refactorings
    21. MegaMart is Creating a Communications Team
    22. Deriving map() from Examples
    23. Functional Tool: map()
    24. Three Ways to Pass a Function
    25. Example: Email Addresses of All Customers
    26. Deriving filter() from Examples
    27. Functional Tool: filter()
    28. Example: Customers with Zero Purchases
    29. Deriving reduce() from Examples
    30. Functional Tool: reduce()
    31. Example: Concatenating Strings
    32. Things You Can Do With reduce()
    33. Three Functional Tools Compared
    34. Chapter 13: Chaining Functional Tools
    35. The Customer Communications Team Continues
    36. Clarifying Chains, Method 1: Name the Steps
    37. Clarifying Chains, Method 2: Naming the Callbacks
    38. Clarifying Chains: Two Methods Compared
    39. Example: Emails of Customers Who Have Made One Purchase
    40. Refactoring Existing for Loops to Functional Tools
    41. Tip 1: Make Data
    42. Tip 2: Operate on Whole Array at Once
    43. Tip 3: Take Many Small Steps
    44. Tip 3: Take Many Small Steps
    45. Comparing Functional to Imperative Code
    46. Summary of Chaining Tips
    47. Debugging Tips for Chaining
    48. Many Other Functional Tools
    49. reduce() for Building Values
    50. Getting Creative with Data Representation
    51. Line Up Those Dots
    52. Chapter 14: Functional Tools for Nested Data
    53. Higher-Order Functions for Values in Objects
    54. Making the Field Name Explicit
    55. Deriving update()
    56. Using update() to Modify Values
    57. Refactoring: Replace Get, Modify, Set with update()
    58. Functional Tool: update()
    59. Visualizing Values in Objects
    60. Visualizing Nested Updates
    61. Applying update() to Nested Data
    62. Deriving updateOption()
    63. Deriving update2()
    64. Visualizing update2() on Nested Objects
    65. Writing incrementSizeByName() Four Ways
    66. Deriving update3()
    67. Deriving nestedUpdate()
    68. The Anatomy of Safe Recursion
    69. Visualizing nestedUpdate()
    70. The Superpower of Recursion
    71. Design Considerations with Deep Nesting
    72. Abstraction Barriers on Deeply Nested Data
    73. A Summary of Our Use of Higher-Order Functions
    74. Chapter 15: Isolating Timelines
    75. There’s a Bug!
    76. Now We Can Try to Click Twice Fast
    77. The Timeline Diagram Shows What Happens Over Time
    78. The Two Fundamentals Of Timeline Diagrams
    79. Two Tricky Details About the Order of Actions
    80. Drawing the Add-to-Cart Timeline: Step 1
    81. Asynchronous Calls Require New Timelines
    82. Different Languages, Different Threading Models
    83. Building the Timeline Step-by-Step
    84. Drawing the Add-to-Cart Timeline: Step 2
    85. Timeline Diagrams Capture the Two Kinds of Sequential Code
    86. Timeline Diagrams Capture the Uncertain Ordering of Parallel Code
    87. Principles of Working with Timelines
    88. JavaScript’s Single-Thread
    89. JavaScript’s Asynchronous Queue
    90. AJAX and the Event Queue
    91. A complete asynchronous example
    92. Simplifying the Timeline
    93. Reading Our Finished Timeline
    94. Simplifying the Add-to-Cart Timeline Diagram: Step 3
    95. Review: Drawing the Timeline (Steps 1–3)
    96. Summary: Drawing Timeline Diagrams
    97. Timeline Diagrams Side-by-Side Can Reveal Problems
    98. Two Slow Clicks Get the Right Result
    99. Two Fast Clicks Can Get the Wrong Result
    100. Timelines That Share Resources Can Cause Problems
    101. Converting a Global Variable to a Local One
    102. Converting a Global Variable to an Argument
    103. Making Our Code More Reusable
    104. Principle: In an Asynchronous Context, We Use a Final Callback Instead of a Return Value as Our Explicit Output
    105. Chapter 16: Sharing Resources Between Timelines
    106. Principles of Working with Timelines
    107. The Shopping Cart Still Has a Bug
    108. We Need to Guarantee the Order of the DOM Updates
    109. Building a Queue in JavaScript
    110. Principle: Use Real-World Sharing as Inspiration
    111. Making the Queue Reusable
    112. Analyzing the Timeline
    113. Principle: Analyze the Timeline Diagram to Know If There Will Be Problems
    114. Making the Queue Skip
    115. Chapter 17: Coordinating Timelines
    116. Principles of Working with Timelines
    117. There’s a Bug!
    118. How the Code was Changed
    119. Identify Actions: Step 1
    120. Draw Each Action: Step 2
    121. Simplify the Diagram: Step 3
    122. Possible Ordering Analysis
    123. Why this Timeline is Faster
    124. Waiting for Both Parallel Callbacks
    125. A Concurrency Primitive for Cutting Timelines
    126. Using Cut() in Our Code
    127. Uncertain Ordering Analysis
    128. Parallel Execution Analysis
    129. Multiple-Click Analysis
    130. A Primitive to Call Something Just Once
    131. Implicit Versus Explicit Model of Time
    132. Summary: Manipulating Timelines
    133. Chapter 18: Reactive and Onion Architectures
    134. Two Separate Architectural Patterns
    135. Coupling of Causes and Effects of Changes
    136. What is Reactive Architecture?
    137. Tradeoffs of the Reactive Architecture
    138. Cells are First-Class State
    139. We Can Make Valuecells Reactive
    140. We Can Update Shipping Icons When the Cell Changes
    141. FormulaCells Calculate Derived Values
    142. Mutable State in Functional Programming
    143. How Reactive Architecture Reconfigures Systems
    144. Decouples Effects from Their Causes
    145. Decoupling Manages a Center of Cause and Effect
    146. Treat Series of Steps as Pipelines
    147. Flexibility in Your Timeline
    148. Two Separate Architectural Patterns
    149. What is the Onion Architecture?
    150. Review: Actions, Calculations, and Data
    151. Review: Stratified Design
    152. Traditional Layered Architecture
    153. A Functional Architecture
    154. Facilitating Change and Reuse
    155. Examine the Terms Used to Place the Rule in a Layer
    156. Analyze Readability and Awkwardness
    157. Chapter 19: The Functional Journey Ahead
    158. A Plan for the Chapter
    159. We Have Learned the Skills of Professionals
    160. Big Takeaways
    161. The Ups and Downs of Skill Acquisition
    162. Parallel Tracks to Mastery
    163. Sandbox: Start a Side Project
    164. Sandbox: Practice Exercises
    165. Production: Eliminate a Bug Today
    166. Production: Incrementally Improve the Design
    167. Popular Functional Languages
    168. Functional Languages with the Most Jobs
    169. Functional Languages by Platform
    170. Functional Languages by Learning Opportunity
    171. Get Mathy
    172. Further Reading
  13. Index