DEV Community

Cover image for Book notes: Grokking Simplicity
Dan Lebrero
Dan Lebrero

Posted on • Originally published at danlebrero.com on

Book notes: Grokking Simplicity

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.

onion layers architecture

TOC

Chapter 1: Welcome to Grokking Simplicity

  • Book explains the two main functional programming (FP) skills:
    1. Distinguish actions, calculations, and data.
      • Actions: anything that depend on when they are called or how many times they are called.
    2. Using first-class abstractions.

Chapter 2: Functional Thinking in Action

  • Stratified design:
    1. Business layer: Least stable.
    2. Domain layer.
    3. 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.
  • 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.
  • 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.
  • "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???
    • 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:
    1. Make data:
      • Transform code into data so that you can name and inspect.
    2. Operate on the whole array:
      • Try to process uniformly.
    3. Many small steps:
      • Prefer small simple step to big complex ones.
    4. Replace conditionals with filter().

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:

timeline diagram example

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. onion architecture onion layers architecture
  • Do domain rules need actions?

    • No. You can always implement it as calculations.
    • In truth, it depends on:
      1. The terms used to place the rule in a layer.
        • Domain language in DDD sense.
      2. Readability and awkwardness:
        • Some programming languages makes a non-functional implementation many times clearer.
        • Take technical debt.
        • System performance.

Top comments (0)