A video series exploring functional programming and Swift.
#73 • Monday Sep 23, 2019 • Subscriber-only

Modular State Management: View State

While we’ve seen that each reducer we’ve written is super modular, and we were easily able to extract each one into a separate framework, our views are still far from modular. This week we address this by considering: what does it mean to transform the state a view has access to?

This episode builds on concepts introduced previously:

#73 • Monday Sep 23, 2019 • Subscriber-only

Modular State Management: View State

While we’ve seen that each reducer we’ve written is super modular, and we were easily able to extract each one into a separate framework, our views are still far from modular. This week we address this by considering: what does it mean to transform the state a view has access to?

This episode builds on concepts introduced previously:


Subscribe to Point‑Free

This episode is for subscribers only. To access it, and all past and future episodes, become a subscriber today!

See subscription optionsorLog in

Sign up for our weekly newsletter to be notified of new episodes, and unlock access to any subscriber-only episode of your choosing!

Sign up for free episode

Introduction

The ease at which we modularized these reducers speaks to just how modular this architecture is by default. We didn’t have to make any striking refactors or changes to logic because the boundaries are already very clearly defined. The worst things got was the need to introduce a little extra boilerplate for a component that had more complex state.

Subscribe to Point-Free

👋 Hey there! Does this episode sound interesting? Well, then you may want to subscribe so that you get access to this episodes and more!


Exercises

  1. Another way to isolate code is to move it to its own file and mark part of it private or fileprivate. How does this kind of modularization differ from using an actual Swift module?

  2. In this episode we discussed how it was not appropriate to give the name map to the transformation we defined on Store due to the trickiness of reference types. Let’s explore defining map on another type with reference semantics.

    Previously on Point-Free, we defined a Lazy type as a struct around a function that returns a value:

    struct Lazy<A> {
      let run: () -> A
    }
    

    Upgrade this struct to a class so that we can introduce memoization. A call to run should perform the given closure and cache the return value so that any repeat calls to run can immediately return this cached value. It should behave as follows:

    import Foundation
    
    let slow = Lazy<Int> {
      sleep(1)
      return 1
    }
    slow.run() // Returns `1` after a second
    slow.run() // Returns `1` immediately
    

    From here, define map on Lazy:

    extension Lazy {
      func map<B>(_ f: @escaping (A) -> B) -> Lazy<B> {
        fatalError("Unimplemented")
      }
    }
    

    Given our discussion around map on the Store type, is it appropriate to call this function map?

  3. Sometimes it can be useful to view into a store so that it removes all access to the underlying state of the store. For example, a “debug” screen for your app could have a UI for listing out every single action in your application as buttons, and tapping the button will send the action to the store. Such a screen doesn’t need any access to the app state.

    Try building such a screen, and provide it view of the store that removes all access to the underlying app state.

  4. Write a function that transforms a Store<GlobalValue, GlobalAction> into a Store<GlobalValue, LocalAction>. That is, a function of the following signature:

    extension Store {
      func view<LocalAction>(
        /* what arguments are needed? */
        ) -> Store<Value, LocalAction> {
    
        fatalError("Unimplemented")
      }
    }
    

    What kind of data does the function need to be supplied with in addition to a store? Is this kind of transformation familiar? Does it have a name we’ve used before on Point-Free?


References

Chapters
Introduction
00:06
Modularizing our views
00:44
Transforming a store's value
04:06
A familiar-looking function
09:23
What's in a name?
14:17
Propagating global changes locally
17:56
Focusing on view state
22:38
Till next time
27:09