Grokking Simplicity: Taming complex software with functional thinking

This document was uploaded by one of our users. The uploader already confirmed that they had the permission to publish it. If you are author/publisher or own the copyright of this documents, please report to us by using this DMCA report form.

Simply click on the Download Book button.

Yes, Book downloads on Ebookily are 100% Free.

Sometimes the book is free on Amazon As well, so go ahead and hit "Search on Amazon"

Distributed across servers, difficult to test, and resistant to modification—modern software is complex. Grokking Simplicity is a friendly, practical guide that will change the way you approach software design and development. It introduces a unique approach to functional programming that explains why certain features of software are prone to complexity, and teaches you the functional techniques you can use to simplify these systems so that they’re easier to test and debug. about the technology Developers rightly fear the unintended complexity that infects most code. This book shows you how to write software that keeps complexity close to its inherent minimum. As you write software you should distinguish between code that alters your system’s state, and code that does not. Once you learn to make that distinction, you can refactor much of your state-altering “actions” into stateless “calculations.” Your software will be simpler. About the book 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. What's inside • Patterns for simpler code • Powerful time modeling approaches to simplify asynchronous code • How higher-order functions can make code reusable and composable About the reader For intermediate and advanced developers building complex software. Exercises, illustrations, self-assessments, and hands-on examples lock in each new idea. About the author Eric Normand is an expert software developer who has been an influential teacher of functional programming since 2007.

Author(s): Eric Normand
Edition: 1
Publisher: Manning Publications
Year: 2021

Language: English
Commentary: Vector PDF
Pages: 592
City: Shelter Island, NY
Tags: Software Engineering; JavaScript; Web Applications; Concurrency; Functional Programming; Asynchronous Programming; Distributed Systems; Callback Functions; Software Architecture; Complexity; Architecture Patterns; Design Thinking

foreword
preface
acknowledgments
about this book
about the author
Welcome to Grokking Simplicity
What is functional programming?
The problems with the definition for practical use
The definition of FP confuses managers
We treat functional programming as a set of skills and concepts
Distinguishing actions, calculations, and data
Functional programmers distinguish code that matters when you call it
Functional programmers distinguishinert data from code that does work
Functional programmers seeactions, calculations, and data
The three categories of code in FP
How does distinguishingactions, calculations, and data help us?
Why is this book different from other FP books?
What is functional thinking?
Ground rules for ideas and skills in this book
Conclusion
Summary
Up next . . .
Functional thinking in action
Welcome to Toni’s Pizza
Part 1: Distinguishing actions, calculations, and data
Organizing code by “rate of change”
Part 2: First-class abstractions
Timelines visualize distributed systems
Multiple timelines can execute in different orderings
Hard-won lessons about distributed systems
Cutting the timeline:Making the robots wait for each other
Positive lessons learned about timelines
Conclusion
Summary
Up next . . .
Distinguishing actions, calculations, and data
Actions, calculations, and data
Actions, calculations, and data apply to any situation
Lessons from our shopping process
Deep dive: Data
Applying functional thinking to new code
Drawing the coupon email process
Implementing the coupon email process
Applying functional thinking to existing code
Actions spread through code
Actions can take many forms
Deep dive: Actions
Conclusion
Summary
Up next . . .
Extracting calculations from actions
Welcome to MegaMart.com!
Calculating free shipping
Calculating tax
We need to make it more testable
We need to make it more reusable
Distinguishing actions, calculations, and data
Functions have inputs and outputs
Testing and reuse relate to inputs and outputs
Extracting a calculation from an action
Extracting another calculation from an action
Let’s see all of our code in one place
Conclusion
Summary
Up next . . .
Improving the design of actions
Aligning design with business requirements
Aligning the function with business requirements
Principle:Minimize implicit inputs and outputs
Reducing implicit inputs and outputs
Giving the code a once-over
Categorizing our calculations
Principle:Design is about pulling things apart
Improving the design by pulling add_item() apart
Extracting a copy-on-write pattern
Using add_item()
Categorizing our calculations
Smaller functions and more calculations
Conclusion
Summary
Up next . . .
Staying immutablein a mutable language
Can immutability be applied everywhere?
Categorizing operations into reads, writes, or both
The three steps of the copy-on-write discipline
Converting a write to a read with copy-on-write
Complete diff from mutating to copy-on-write
These copy-on-write operations are generalizable
JavaScript arrays at a glance
What to do if an operation is a read and a write
Splitting a function that does a read and write
Returning two values from one function
Reads to immutable data structures are calculations
Applications have state that changes over time
Immutable data structures are fast enough
Copy-on-write operations on objects
JavaScript objects at a glance
Converting nested writes to reads
What gets copied?
Visualizing shallow copies and structural sharing
Conclusion
Summary
Up next . . .
Staying immutable with untrusted code
Immutability with legacy code
Our copy-on-write code has to interact with untrusted code
Defensive copying defends the immutable original
Implementing defensive copies
The rules of defensive copying
Wrapping untrusted code
Defensive copying you may be familiar with
Copy-on-write and defensive copying compared
Deep copies are more expensive than shallow copies
Implementing deep copy in JavaScript is difficult
A dialogue between copy-on-write and defensive copying
Conclusion
Summary
Up next . . .
Stratified design:Part 1
What is software design?
What is stratified design?
Developing our design sense
Patterns of stratified design
Pattern 1: Straightforward implementations
Three different zoom levels
Extracting the for loop
Pattern 1 Review: Straightforward implementation
Conclusion
Summary
Up next . . .
Stratified design: Part 2
Patterns of stratified design
Pattern 2: Abstraction barrier
Abstraction barriers hide implementations
Ignoring details is symmetrical
Swapping the shopping cart’s data structure
Re-implementing the shopping cart as an object
The abstraction barrier lets us ignore details
When to use (and when not to use!) abstraction barriers
Pattern 2 Review: Abstraction barrier
Our code is more straightforward
Pattern 3: Minimal interface
Pattern 3 Review: Minimal interface
Pattern 4: Comfortable layers
Patterns of stratified design
What does the graph show us about our code?
Code at the top of the graph is easier to change
Testing code at the bottom is more important
Code at the bottom is more reusable
Summary: What the graph shows us about our code
Conclusion
Summary
Up next . . .
First-class functions: Part 1
Marketing still needs to coordinate with dev
Code smell: Implicit argument in function name
Refactoring: Express implicit argument
Recognize what is and what isn’t first-class
Will field names as strings lead to more bugs?
Will first-class fields make the API hard to change?
We will use a lot of objects and arrays
First-class functions can replace any syntax
For loop example: Eating and cleaning up
Refactoring: Replace body with callback
What is this syntax?
Why are we wrapping the code in a function?
Conclusion
Summary
Up next . . .
First-class functions: Part 2
One code smell and two refactorings
Refactoring copy-on-write
Refactoring copy-on-write for arrays
Returning functions from functions
Conclusion
Summary
Up next . . .
Functional iteration
One code smell and two refactorings
MegaMart is creating a communications team
Deriving map() from examples
Functional tool: map()
Three ways to pass a function
Example: Email addresses of all customers
Deriving filter() from examples
Functional tool: filter()
Example: Customers with zero purchases
Deriving reduce() from examples
Functional tool: reduce()
Example: Concatenating strings
Things you can do with reduce()
Three functional tools compared
Conclusion
Summary
Up next . . .
Chaining functional tools
The customer communications team continues
Clarifying chains, method 1: Name the steps
Clarifying chains, method 2: Naming the callbacks
Clarifying chains: Two methods compared
Example: Emails of customers who have made one purchase
Refactoring existing for loops to functional tools
Tip 1: Make data
Tip 2: Operate on whole array at once
Tip 3: Take many small steps
Tip 3: Take many small steps
Comparing functional to imperative code
Summary of chaining tips
Debugging tips for chaining
Many other functional tools
reduce() for building values
Getting creative with data representation
Line up those dots
Conclusion
Summary
Up next . . .
Functional tools for nested data
Higher-order functions for values in objects
Making the field name explicit
Deriving update()
Using update() to modify values
Refactoring: Replace get, modify, set with update()
Functional tool: update()
Visualizing values in objects
Visualizing nested updates
Applying update() to nested data
Deriving updateOption()
Deriving update2()
Visualizing update2() on nested objects
Writing incrementSizeByName() four ways
Deriving update3()
Deriving nestedUpdate()
The anatomy of safe recursion
Visualizing nestedUpdate()
The superpower of recursion
Design considerations with deep nesting
Abstraction barriers on deeply nested data
A summary of our use of higher-order functions
Conclusion
Summary
Up next . . .
Isolating timelines
There’s a bug!
Now we can try to click twice fast
The timeline diagram shows what happens over time
The two fundamentals of timeline diagrams
Two tricky details about the order of actions
Drawing the add-to-cart timeline: Step 1
Asynchronous calls require new timelines
Different languages, different threading models
Building the timeline step-by-step
Drawing the add-to-cart timeline: Step 2
Timeline diagrams capture the two kinds of sequential code
Timeline diagrams capture the uncertain ordering of parallel code
Principles of working with timelines
JavaScript’s single-thread
JavaScript’s asynchronous queue
AJAX and the event queue
A complete asynchronous example
Simplifying the timeline
Reading our finished timeline
Simplifying the add-to-cart timeline diagram: Step 3
Review: Drawing the timeline (steps 1–3)
Summary: Drawing timeline diagrams
Timeline diagrams side-by-side can reveal problems
Two slow clicks get the right result
Two fast clicks can get the wrong result
Timelines that share resources can cause problems
Converting a global variable to a local one
Converting a global variable to an argument
Making our code more reusable
Principle: In an asynchronous context, we use a final callback instead of a return value as our explicit output
Conclusion
Summary
Up next . . .
Sharing resources between timelines
Principles of working with timelines
The shopping cart still has a bug
We need to guarantee the order of the DOM updates
Building a queue in JavaScript
Principle:Use real-world sharing as inspiration
Making the queue reusable
Analyzing the timeline
Principle:Analyze the timeline diagram to know if there will be problems
Making the queue skip
Conclusion
Summary
Up next . . .
Coordinating timelines
Principles of working with timelines
There’s a bug!
How the code was changed
Identify actions: Step 1
Draw each action: Step 2
Simplify the diagram: Step 3
Possible ordering analysis
Why this timeline is faster
Waiting for both parallel callbacks
A concurrency primitive for cutting timelines
Using Cut() in our code
Uncertain ordering analysis
Parallel execution analysis
Multiple-click analysis
A primitive to call something just once
Implicit versus explicit model of time
Summary: Manipulating timelines
Conclusion
Summary
Up next . . .
Reactive and onion architectures
Two separate architectural patterns
Coupling of causes and effects of changes
What is reactive architecture?
Tradeoffs of the reactive architecture
Cells are first-class state
We can make ValueCells reactive
We can update shipping icons when the cell changes
FormulaCells calculate derived values
Mutable state in functional programming
How reactive architecture reconfigures systems
Decouples effects from their causes
Decoupling manages a center of cause and effect
Treat series of steps as pipelines
Flexibility in your timeline
Two separate architectural patterns
What is the onion architecture?
Review: Actions, calculations, and data
Review: Stratified design
Traditional layered architecture
A functional architecture
Facilitating change and reuse
Examine the terms used to place the rule in a layer
Analyze readability and awkwardness
Conclusion
Summary
Up next . . .
The functional journey ahead
A plan for the chapter
We have learned the skills of professionals
Big takeaways
The ups and downs of skill acquisition
Parallel tracks to mastery
Sandbox: Start a side project
Sandbox: Practice exercises
Production: Eliminate a bug today
Production: Incrementally improve the design
Popular functional languages
Functional languages with the most jobs
Functional languages by platform
Functional languages by learning opportunity
Get mathy
Further reading
Conclusion
Summary
Up next . . .
index