Modular State Management: The Point

Episode #75 • Oct 7, 2019 • Subscriber-Only

We’ve now fully modularized our app by extracting its reducers and views into their own modules. Each screen of our app can be run as a little app on its own so that we can test its functionality, all without needing to know how it’s plugged into the app as a whole. And this is the point of modular state management!

The Point
Introduction
00:05
What’s the point?
01:24
The favorite primes app
04:01
The prime modal app
06:24
The counter app
07:45
Fixing the root app
13:25
Conclusion
18:07

Unlock This Episode

Our Free plan includes 1 subscriber-only episode of your choice, plus weekly updates from our newsletter.

Introduction

Alright, we’ve now accomplished what we set out to do at the beginning of this series of episodes on modular state management. First, we defined what “modular” meant: we determined that modularity was the ability to move code into a literal Swift module so that it is completely isolated from the rest of your app. Then we showed just how modular our reducers already were by breaking each one off into a framework of its own. Finally, in order to modularize our views we discovered two forms of composition on the Store type: one that allowed us to focus an existing store on some subset of state, and another that allowed us to focus an existing store on some subset of actions. These operations allowed us to separate all of our views from more global, app-level concerns and move them into isolated modules of their own.

This episode is for subscribers only.

Subscribe to Point-Free

Access this episode, plus all past and future episodes when you become a subscriber.

See plans and pricing

Already a subscriber? Log in

Exercises

  1. So far it has been very easy to tap into SwiftUI’s button actions in order to send those actions to the store. However, not all SwiftUI actions are that easy. For instance, TextFields do not expose closures for us to implement that will be notified when text is changed in the field. Instead, they use Binding<String> values, which are 2-way bindings that allow you to simulataneously change the text field’s value and observe text field changes.

    This model unfortauntely does not fit our architecture since we prefer all mutations of state go through our store and reducer. However, it’s easy to fix! Implement the following function on Store, which allows you to construct a Binding by providing a way to construct an Action from the binding value and a way to extract a binding value from our store’s value:

    extension Store {
      public func send<LocalValue>(
        _ event: @escaping (LocalValue) -> Action,
        binding keyPath: KeyPath<Value, LocalValue>
      ) -> Binding<LocalValue> {
        fatalError("Unimplemented")
      }
    }
    

    We have decided to call this method send so that it mimics the standard send method on Store. This means that you can simply search for store.send in your application to find all places where user actions feed into the architecture.

  2. Using the send implementation from the previous exercise, change the Text view that holds the counter into a TextField, which would allow the user to enter any number they want. To accomplish this you will need to introduce a new counter action counterTextFieldChanged(String) in order to be notified when the user types into the field.

References

Playground Driven Development

Brandon Williams & Stephen Celis • Monday Jul 9, 2018

This week’s episode took “playground-driven development” to the next level by showing that a fully modularized app allows each of its screens to be run in isolation like a mini-app on its own. Previously we talked about playground-driven development for quickly iterating on screen designs, and showed what is necessary to embrace this style of development.

We use Swift playgrounds on this series as a tool to dive deep into functional programming concepts, but they can be so much more. Today we demonstrate a few tricks to allow you to use playgrounds for everyday development, allowing for a faster iteration cycle.

Playground Driven Development

Brandon Williams • Friday Oct 6, 2017

Brandon gave an in-depth talk on playground driven development at FrenchKit 2017. In this talk he shows what it takes to get a codebase into shape for this style of development, and shows off some of the amazing things you can do once you have it.

Playground Driven Development at Kickstarter

Brandon Williams • Friday May 19, 2017

We pioneered playground driven development while we were at Kickstarter, where we replaced the majority of our use for storyboards with playgrounds. It takes a little bit of work to get started, but once you do it really pays dividends. In this Swift Talk episode, Brandon sits down with Chris Eidhof to show the ins and outs of playground driven development.

Why Functional Programming Matters

John Hughes • Saturday Apr 1, 1989

A classic paper exploring what makes functional programming special. It focuses on two positive aspects that set it apart from the rest: laziness and modularity.

Elm: A delightful language for reliable webapps

Elm is both a pure functional language and framework for creating web applications in a declarative fashion. It was instrumental in pushing functional programming ideas into the mainstream, and demonstrating how an application could be represented by a simple pure function from state and actions to state.

Redux: A predictable state container for JavaScript apps.

The idea of modeling an application’s architecture on simple reducer functions was popularized by Redux, a state management library for React, which in turn took a lot of inspiration from Elm.

Composable Reducers

Brandon Williams • Tuesday Oct 10, 2017

A talk that Brandon gave at the 2017 Functional Swift conference in Berlin. The talk contains a brief account of many of the ideas covered in our series of episodes on “Composable State Management”.