Handle Pending File Changes with ReSwift as Your Backbone

Teaser image

Automatic saving of changes in some user interface component to a file should be handled differently when you employ ReSwift. In short, you have to extract the state information from the “save file” action and store it in the overall app’s state somehow. I append these to a collection of PendingFileChanges, a ReSwift.StateType that is part of my overall app state.

Continue reading …

RocketData is a Uni-Directional UI Component Data Source

I watched “Managing Consistency of Immutable Models” by Peter Livesey where Peter shows how RocketData works. Very worth the time! I’d call RocketData a uni-directional data source. It’s uni-directional because you set up the DataProvider as the source once, wire update notifications to view updates via the delegate property, and you’re done with the setup. Update events include:

Continue reading …

Comment On "Real World Flux Architecture on iOS"

The Flux architecture Benjamin Encz describes for the PlanGrid iOS app is like ReSwift only on a per-component basis: the user interactions fire change events that a store takes care of to mutate its state. The state then becomes the input for the view again.

It’s much like MVVM, whereas here the view model is the store’s state.

This Flux-like approach is still a big improvement over convoluted view controllers or not thinking about data flow at all. But I wonder if the gain is so much higher compared to properly separated MVC. Who reads the store’s state? Only the views? Then the state is truly a view model; but how do side-effect populate to the rest of the app, like renaming or deleting things? I’d tend towards dispatching the change event to other stores, too, which may or may not react to the event. Then the view component’s state is updated independently from the database, say, using the same event dispatch mechanism.

To model the flow of truth on a component basis (which is still uni-directional: from store to view) compared to a single global app state (ReSwift) sounds like a very easy to do component redesign. You can start with anything and “fluxify” it. Then move on to the next component that’s particularly convoluted. You may not even want to convert all your components to this data flow approach when some components are simple enough as they are. Symmetry of component design will suffer, of course, but if you’re aware of this and conclude it’s better not to convert everything, that’s fine.

With ReSwift, I interpret the global app state to be a state with real (Domain) Model objects. To make a state displayable, I derive view models from it. This came very natural to me. But Ben’s posts got me thinking: could there be situations where keeping view model state around is better than keeping “real” model state?

When You Code, You Design Both Structure and Information Flow

As soon as you write a piece of software, you “architect” it. Can’t get around that; but if you do not do it consciously, the resulting structure may not be great. Taking ownership of the process is important to change the result and create maintainable software. When we write/architect software, we worry about two things:

Continue reading …

I'll Split Up the Monolithic View Model in TableFlip. Here's What I Expect to Happen

The upcoming changes in TableFlip’s user experience made me ponder how I structured the app’s modules. The bottleneck I created in my app is simple: there’s one presenter which transforms the model into a view model; the presenter defines a protocol for the view it expects and passes the view model to the object that satisfies this contract.

Continue reading …

How PlanGrid uses a Flux-Inspired Architecture to Simplify State Management

Benjamin Encz published an article about the architecture of PlanGrid.

They moved to a Flux-inspired “unidirectional flow” approach where state changes are performed in a Store (in the backend, if you will) and updates pushed to the user interface (the frontend). No ad-hoc view updates, no shortcuts. User events are emitted, handled by the store, and state updates affect the view. That’s it. So it’s always obvious how the user interface got into the state it’s in: all the details are plainly visible in the current state object.

Ben’s post is very deep and detailed. You’ll learn a ton from it:

  • architectural discussion: why “unidirection flow”, and why Flux?
  • setup of actions/events and the store type
  • basic state–view bindings via Reactive Cocoa
  • how testing stores (and views) is straightforward with this setup

I can’t wait for the next post in this series. Most of this easily applies to ReSwift, too, of course. And guess who just got inspired to refactor TableFlip so the model and view become even more loosely coupled?

Separating ReSwift Actions from UI Events

Teaser image

Today was the second time during the development of TableFlip that I started to implement a new feature in the wrong way: starting with an explicit event type that is triggered by pressing a button in the user interface. This is a 1:1 mapping of user intent to an event that performs changes in the model. Next time I’ll start from another point of view instead to not rush too many minuscule changes until I hit a roadblock and hate myself. Here’s what went wrong.

Continue reading …

ReSwift, Law of Demeter, and Another Level of Indirection

Teaser image

Benjamin Encz’s presentation “Unidirectional Data Flow in Swift” about ReSwift features global app state: there’s one AppState type that acts as the facade to model and navigation state which is the single point of truth of every state in the app. This is a game changer when you suffer from massive view controller syndrome. In this post, I’d like to show you how he envisions the state of an app and what a next step could look like.

Continue reading …

Events as Declarative State

Teaser image

I think I found something better than closures to handle events. Instead of dispatching closures that are themselves the changes that should be performed, simply declare the change.

enum Action {
    case ResizeBanana(BananaId, Size)

Now you need some kind of action handler, which Benjamin Encz calls “reducer” in his presentation “Unidirectional Data Flow in Swift”. Think of a list of reducers as a Chain of Responsibility only without the final consummation of the action. It is passed throughout the whole responder chain. Why reducer? Because they operate similar to the reduce function. The end result will be the combined result of all reducer’s mutations.

This is cool, because no component needs to know what such an action entails – none except the appropriate reducers.

If closures were great because where you type them you can see what is going on (more like “how” in my opinion), a simple action enum is even simpler, telling what should happen.

Works well with CQRS, I imagine. Will have to write a demo app using CQRS sometime to validate.

The current project is called ReSwift and code is available on GitHub.