Book notes: Grokking Simplicity
Book notes on "Grokking Simplicity" by Eric Normand
These are my notes on Grokking Simplicity by Eric Normand.
Excellent introduction to functional programming, or at least how I understand it.
Key Insights
- World is divided in actions, calculations, and data.
- Actions: anything that depend on when they are called or how many times they are called.
- Data is useful mostly because of what it can’t do: it cannot be run.
- Reads to mutable data are actions.
- Reads to immutable data are calculations.
- Groups actions by layers of meaning.
- Principle: design is about pulling things apart.
- Code within a function should have the same level of detail.
- Being able to ignore the same details is one clue that the code is at similar level of abstraction.
- Don’t move unclear code to another layer, make it straightforward.
- Design discussions run the risk of getting too abstract.
- We often write a lot of code just in case something might change in the future.
- There is constant tension between design and the need for new features. Let comfort guide you when to stop.
- A function cannot call other functions in its same layer.
- Simplify collection processing:
- Transform code into data so that you can name and inspect.
- Prefer small simple step to big complex ones.
- Use abstraction barrier on deeply nested data to reduce cognitive load.
TOC
- Chapter 1: Welcome to Grokking Simplicity
- Chapter 2: Functional Thinking in Action
- Part 1: Actions, calculations, and data.
- Part 2: First-class abstractions
Chapter 1: Welcome to Grokking Simplicity
- Book explains the two main functional programming (FP) skills:
- Distinguish actions, calculations, and data.
- Actions: anything that depend on when they are called or how many times they are called.
- Using first-class abstractions.
- Distinguish actions, calculations, and data.
Chapter 2: Functional Thinking in Action
- Stratified design:
- Business layer: Least stable.
- Domain layer.
- Tech stack layer: Most stable.
Part 1: Actions, calculations, and data.
Chapter 3: Distinguishing actions, calculations, and data
- Data:
- Facts about events.
- Is useful mostly because of what it can’t do: it cannot be run.
- Must be interpreted to be useful.
Chapter 5: Improving the design of actions
- Principle: minimize implicit inputs and outputs.
- Code is more reusable.
- Choose better level of abstraction: closer function/parameters names to business language (ubiquitous language from DDD).
- Groups actions by layers of meaning.
- Principle: design is about pulling things apart.
Chapter 6: Staying immutable in a mutable language
- Reads to mutable data are actions.
- Reads to immutable data are calculations.
Chapter 8: Stratified design: Part 1
- Software design: using one’s aesthetic sense to guide programming choices to improve the ease of coding, testing, and maintaining software.
- Stratified design:
- Pattern 1: straightforward implementation.
- Code within a function should have the same level of detail. This is the Composed Method in Implementation Patterns.
- Being able to ignore the same details is one clue that the code is at similar level of abstraction.
- If a layer is using for its implementation several other layers, then it is not straightforward implementation.
- Don’t move unclear code to another layer, make it straightforward.
- Pattern 1: straightforward implementation.
- Design discussions run the risk of getting too abstract.
Chapter 9: Stratified design: Part 2
- Stratified design:
- Pattern 2: Abstraction barrier.
- A layer that let us ignore the same thing when working above that layer.
- Most important benefit: they let you think more easily about the problem you are trying to solve.
- Pattern 2: Abstraction barrier.
- Warn: we often write a lot of code just in case something might change in the future.
- Pattern 3: Minimal interface.
- It ask us to consider where code for new features belong.
- A function cannot call other functions in its same layer (really??).
- Pattern 4: Comfortable layers.
- No codebase is ideal.
- There is constant tension between design and the need for new features. Let comfort guide you when to stop.
- Pattern 3: Minimal interface.
- “Ilities”:
- Maintainability: code at the top layers is easier to test.
- Testability: code at the bottom layers is more important to test.
- Because it changes less frequently and all other code depends on it.
- Do I strongly disagree???
- Because it changes less frequently and all other code depends on it.
- Reusability: code at the bottom layers is more reusable.
Part 2: First-class abstractions
Chapter 10: First-class functions: Part 1
- Code smell: implicit argument in function name:
- Similar function implementation.
- Name of function indicates the difference in implementation.
- Refactoring: express implicit argument:
- Argument becomes first-class and part of the API.
- Treat data as data (data orientation):
- Bespoke interfaces allow one interpretation of data while prohibiting others == less reusable.
- Entities at the bottom layers should be reusable/generic.
- Refactoring: replace body with callback.
Chapter 13: Chaining functional tools
- Simplify collection processing:
- Make data:
- Transform code into data so that you can name and inspect.
- Operate on the whole array:
- Try to process uniformly.
- Many small steps:
- Prefer small simple step to big complex ones.
- Replace conditionals with
filter()
.
- Make data:
Functional tools for nested data
- Use abstraction barrier on deeply nested data to reduce cognitive load.
Isolating timelines
- Timeline diagram:
- Sequence of actions.
- Show sequential or parallel execution.
- From Manning site:
Sharing resources between parallel execution
- Queue to guarantee order.
Reactive and onion architecture
- Reactive architecture:
- Instead of “Do X then do Y”, it says “Do Y when X happens”.
- Atom watchers: when atom value changes, do Y.
- ReactiveManifesto.org
- Onion architecture:
- Layers can only call/know about inner layers.
Do domain rules need actions?
- No. You can always implement it as calculations.
- In truth, it depends on:
- The terms used to place the rule in a layer.
- Domain language in DDD sense.
- Readability and awkwardness:
- Some programming languages makes a non-functional implementation many times clearer.
- Take technical debt.
- System performance.
- The terms used to place the rule in a layer.