Grokking Simplicity
Taming complex software with functional thinking
Eric Normand
  • MEAP began August 2019
  • Publication in Early 2021 (estimated)
  • ISBN 9781617296208
  • 325 pages (estimated)
  • printed in black & white

A very accessible introduction to functional programming for developers who don't already know anything about it.

Kent Spillner
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.

Available in PDF (ePub, kindle, and liveBook formats coming soon).

About the Technology

Even experienced developers struggle with software systems that sprawl across distributed servers and APIs, are filled with redundant code, and are difficult to reliably test and modify. Adopting ways of thinking derived from functional programming can help you design and refactor your codebase in ways that reduce complexity, rather than encouraging it. Grokking Simplicity lays out how to use functional programming in a professional environment to write a codebase that’s easier to test and reuse, has fewer bugs, and is better at handling the asynchronous nature of distributed systems.

About the book

In Grokking Simplicity, you’ll learn techniques and, more importantly, a mindset that will help you tackle common problems that arise when software gets complex. Veteran functional programmer Eric Normand guides you to a crystal-clear understanding of why certain features of modern software are so prone to complexity and introduces you to the functional techniques you can use to simplify these systems so that they’re easier to read, test, and debug. Through hands-on examples, exercises, and numerous self-assessments, you’ll learn to organize your code for maximum reusability and internalize methods to keep unwanted complexity out of your codebase. Regardless of the language you’re using, the ways of thinking in this book will help recognize problematic code and tame even the most complex software.
Table of Contents detailed table of contents

Part 1: Actions, Calculations, and Data

1 Welcome to Grokking Simplicity

What is functional programming?

The problems with the definition for practical use

Problem 1

Problem 2

Problem 3

The definition of functional programming is confusing to 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 distinguish inert data from code that does work

Functional programmers see actions, calculations, and data

The three categories of code in functional programming

How does distinguishing actions, calculations, and data help us?

FP works great for distributed systems, and most software written today is distributed

Why is this book different from other functional programming books?

This book uses real-world scenarios

This book focuses on software design

This book conveys the richness of functional programming

This book is language agnostic

What is functional thinking?

Part 1: Distinguishing actions, calculations, and data

Part 2: Using first-class abstractions

Part 3: Building composable models

Ground rules for ideas and skills in this book

1. The skills can’t be based on language features

2. The skills must have immediate practical benefit

3. The skills must apply regardless of your current code situation

Brain break

Conclusion

Summary

2 Functional thinking in action

Welcome to Toni’s Pizza

Part 1: Distinguishing actions, calculations, and data

Part 2: Using first-class abstractions

Part 3: Building composable models

Part 1: Distinguishing actions, calculations, and data

Actions

Calculations

Data

Organizing code by “rate of change”

A first glimpse of stratified design

Part 2: First-class abstractions

As applied to a robotic kitchen

Timelines help you understand distributed systems

Multiple timelines can execute in different orderings

Hard-won lessons about distributed systems

Toni does a post-mortem

1. Timelines are uncoordinated by default

2. You cannot rely on the duration of actions

3. Bad timing, however rare, can happen in production

4. The timeline diagram reveals problems in the system

Cutting the timeline: Making the robots wait for each other

Positive lessons learned about timelines

Retrospective on coordinating robots

1. Cutting a timeline makes it easy to reason about thepieces in isolation

2. Working with timeline diagrams helps me understand howthe system works through time

3. Timeline diagrams are flexible

Part 3: Building composable models

A first glimpse at modeling a domain with data

Comparing functional programming to an object-oriented approach

A typical object-oriented approach

A typical functional approach

We use data all the time outside of the computer

Representing a recipe as data

Data can be interpreted in many ways

The ingredients list operations evolved into a powerful API

Conclusion

Summary

3 Distinguishing actions, calculations, and data

Actions, calculations, and data

1. Thinking about a problem

2. Coding up a solution

3. Reading code

Actions, calculations, and data apply to any situation (page 1 of 3)

Actions, calculations, and data apply to any situation (page 2 of 3)

check fridge

drive to store

buy what you need

drive home

Actions, calculations, and data apply to any situation (page 3 of 3)

Lessons from our shopping process

1. We can apply the actions, calculations, and data perspective to any situation

2. Actions can hide actions, calculations, and data

3. Calculations can be composed of smaller calculations and data

4. Data can only be composed of more data

5. Calculations often happen “in our heads”

Deep dive: Data

What is data?

How do we implement data?

How does data encode meaning?

What are the advantages of data?

Applying functional thinking to new code

A new marketing tactic at CouponDog

Brainstorm!

Don’t worry about getting the wrong answer. It’s just about exploring the ideas.

Drawing the coupon email process (page 1 of 5)

1. Let’s start with fetching subscribers from the database

2. Fetching the coupons from the database

Drawing the coupon email process (page 2 of 5)

3. Generating the emails to send

4. Sending the emails

Drawing the coupon email process (page 3 of 5)

Zooming into generating emails

Drawing the coupon email process (page 4 of 5)

Zooming into generating emails

Drawing the coupon email process (page 5 of 5)

Zooming into generating emails

Implementing the coupon email process (page 1 of 5)

The subscriber is data from the database

The coupon rank is a string

Deciding a coupon rank is a function

Implementing the coupon email process (page 2 of 5)

The coupon is data from the database

The calculation to select coupons by rank is a function

Implementing the coupon email process (page 3 of 5)

An email is just data

Implementing the coupon email process (page 4 of 5)

The calculation to plan one email for a subscriber

Implementing the coupon email process (page 5 of 5)

Planning all emails

Sending the emails is an action

Brain break

Deep dive: Calculations

What are calculations?

How do we implement calculations?

How do calculations encode meaning?

Why prefer calculations to actions?

What worries do calculations avoid?

Applying functional thinking to existing code

Actions spread through code

Actions can take many forms

Deep dive: Actions

Conclusion

Summary

4 Extracting calculations from actions

Welcome to MegaMart.com!

Where your shopping cart is always full

MegaMart reveals its secret code to you

No NDA required

Calculating free shipping

Your new assignment

The imperative way to do it

Sometimes the imperative way is the most straightforward

Calculating tax

Your next assignment

We need to make it more testable

The code contains business rules that are not easy to test

George from testing’s code notes

George from testing’s suggestions

We need to make it more reusable

The accounting and shipping departments want to use our code

Jenna on dev team’s code notes

Jenna on dev team’s suggestions

Distinguishing actions, calculations, and data

Functions have inputs and outputs

Inputs and outputs can be implicit or explicit

Implicit inputs and outputs make a function an action

Suggestions from George and Jenna

George 1: Separate business rules from DOM updates

George 2: Get rid of global variables

Jenna 1: Don’t depend on global variables

Jenna 2: Don’t assume the answer goes in the DOM

Jenna 3: Return the answer from the function

Extracting a calculation from an action (page 1 of 3)

Extracting a calculation from an action (page 2 of 3)

Extracting a calculation from an action (page 3 of 3)

Extracting out another calculation from an action (page 1 of 3)

Extracting out another calculation from an action (page 2 of 3)

Extracting out another calculation from an action (page 3 of 3)

Brain break

There’s more to go, but let’s take a break for questions

Step-by-step: Extracting a calculation

1. Select and extract the calculation code

2. Identify the implicit inputs and outputs of the function

3. Convert inputs to arguments and outputs to return values

Let’s see all of our code in one place

Conclusion

Summary

5 Improving the design of actions

Improving the design by aligning it with business requirements

Choosing a better level of abstraction that matches its usage

Aligning the function with business requirements (page 1 of 2)

This isn’t refactoring, really, since we’re changing the behavior.

Brain break

There’s more to go, but let’s take a break for questions

Principle: When it comes to implicit inputs and outputs, the fewer, the better

Reducing the implicit inputs and outputs update_shipping_icons()

When it comes to implicit inputs and outputs, the fewer, the better

Giving the code a once-over (page 1 of 2)

Giving the code a once-over (page 2 of 2)

Categorizing our calculations

By grouping our calculations, we can learn something about layers of meaning

Principle: Design is about pulling things apart

Improving the design by pulling add_item() apart

This function might look simple, but we can pull something out

Extracting out a copy-on-write pattern

Using add_item()

Categorizing our calculations

Let’s take another look at what they’re about

Brain break

There’s more to go, but let’s take a break for questions

Smaller functions and more calculations

Conclusion

Summary

6 Staying immutable in a mutable language

Can immutability be applied everywhere?

Categorizing operations into reads, writes, or both

We can categorize an operation as either a read or a write

The three steps of the copy-on-write discipline

Converting a write to a read with copy-on-write

Converting a write to a read with copy-on-write

Converting a write to a read with copy-on-write

Converting a write to a read with copy-on-write

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

Preferred approach for copy-on-write for a read+write

1. Splitting the read and write into two operations

Splitting the operation into read and write

Convert the write into a copy-on-write

Also good approach for copy-on-write for a read+write

2. Returning two values

Wrap up the operation

Convert the read+write to a read

Another option

Brain break

Reads to immutable data structures are calculations

Applications have state that changes over time

Immutable data structures are fast enough

We can always optimize later

Garbage collectors are really fast

Garbage collectors are really fast

We’re not copying as much as you might think at first

Functional programming languages have fast implementations

Copy-on-write operations on Objects

JavaScript Objects at a glance

Converting nested writes to reads

What gets copied?

Arrays: 1 (shopping cart) Objects: 3 (t-shirt, shoes, and socks in cart)

Arrays: 1 (shopping cart) Objects: 1 (t-shirt)

Visualizing shallow copies and structural sharing

Conclusion

Summary

Up next …​

7 Staying immutable with untrusted code

Immutability with legacy code

Our code code has to interact with untrusted code

Defensive copying defends the immutable original

Implementing defensive copies

The rules of defensive copying

Rule 1: Copy as data leaves your code

Rule 2: Copy as data enters your code

Wrapping untrusted code

Defensive copying you may be familiar with

Defensive copying in web APIS

Defensive copying in Erlang and Elixir

Brain break

Copy-on-write and defensive copying compared

Deep copies are much more expensive than shallow copies

Implementing deep copy in JavaScript is difficult

A dialog between copy-on-write and defensive copying

Conclusion

Summary

8 Stratified design, part 1

What is software design?

What is stratified design?

Developing our design sense

Patterns of stratified design

Pattern 1: Straightforward implementations

Desired shopping cart operations

Checking if an item is in the cart can help us

Visualizing our function calls with a call graph

Call functions from a similar layer of abstraction

Brain break

Adding another function to the graph

Brain break

All functions in a layer should serve the same pupose

Three different zoom levels

Arrow length at the layer zoom level

Arrow length at the function zoom level

Extracting out the for loop

Brain break

Pattern 1 Review: Straightforward implementation

Conclusion

Summary

9 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

Reimplementing 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

Two choices for coding the marketing campaign

Implementing the campaign above the barrier is better

Marketing wants to log items added to the cart

The design consequences of code location

A better place to log adds to cart

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

Code at the top of the graph is easier to change

Testing code at the bottom is more important

Testing code at the bottom is more important

Testing code at the bottom is more important

Code at the bottom is more reusable

Summarizing what the graph shows us about NFRs

Conclusion

Summary

Part 2: First-class abstractions

10 Higher-order functions

11 Functional iteration and other patterns

12 Isolating timelines

13 Sharing resources between timelines

14 Going meta with actions

15 Cutting timelines

16 Onion architecture

Part 3: Building composable models

17 Modeling facts with data

18 Modeling change over time with data

19 Modeling changing state with data

20 Modeling operations first

21 Reactive architecture

22 Conclusion

What's inside

  • Apply functional programming principles to reduce codebase complexity
  • Work with data transformation pipelines for code that’s easier to test and reuse
  • Tools for modeling time to simplify asynchrony
  • 60 exercises and 100 questions to test your knowledge

About the reader

For experienced programmers. Examples are in JavaScript.

About the author

Eric Normand has been a functional programmer since 2001 and has been teaching functional programming online and in person since 2007. Visit LispCast.com to see more of his credentials.

placing your order...

Don't refresh or navigate away from the page.
Manning Early Access Program (MEAP) Read chapters as they are written, get the finished eBook as soon as it’s ready, and receive the pBook long before it's in bookstores.
print book $39.99 $49.99 pBook + eBook + liveBook
Additional shipping charges may apply
Grokking Simplicity (print book) added to cart
continue shopping
go to cart

eBook $31.99 $39.99 3 formats + liveBook
Grokking Simplicity (eBook) added to cart
continue shopping
go to cart

Prices displayed in rupees will be charged in USD when you check out.

FREE domestic shipping on three or more pBooks