A single source of truth

Fernando Martín Ortiz
5 min readNov 4, 2019

Note: This article has already been posted on my personal blog.

I’ve been an iOS developer for almost five years. And working as a software engineer, you may know, is something frustrating.
Sure, it’s fulfulling, it’s a creative activity, I know, but it’s also frustrating. One thing I realised with the time
is that your taste evolves faster than your ability.

In my first projects, I followed the only technique I knew: programming imperatively. And it worked. Screens appeared in my
app, with the controls I programmed, and I felt better at the time.

The main characteristic that differentiates a junior developer from a senior one is the understanding of tradeoffs. A senior developer can create code that is scalable over time, and does that when required. He almost always chooses the approach that is complex enough to get the work done, but creating the least amount of accidental complexity in the process.

This introduction may seem a bit longer than needed, but it’s important to take this into account, because there are a lot of tools to solve each problem, and this one is not an exception. Today, I’ll write about the most important issue a UI developer face every day in my opinion: State management.

Our problem

Let’s work with an example. We are working on a calculator that operates on two numbers. The requirements for our simple screen would be:

1. There must be two text fields, so the user can introduce the arguments.
2. There must be a third text field, in which the user can select the operation to be performed.
3. There must be a label where the result will appear.
4. There must be no button. The entire UI should be refreshed on any change that may occur.

What I used to do

So here is what I would have done when I started as a developer.

First, I would have created the outlets for the views (I’ll not specify how the storyboard is done, to be more concise):

Then, I’d have configured the event handlers for my views, and an enum that will be helpful for to describe the operations:

And finally, a method that would have refreshed the views accordingly:

This approach works great for basic tasks. And I insist with this, because there is nothing wrong with it in my opinion. However, if we know that the screen will be more complicated, or if there are more requirements that we haven’t coded yet, we can make some changes to it.

The rule

I have a main rule when it comes to UI software development: There should be a single source of truth, so state is always consistent.

State is a bomb of complexity, that will explode on your face if you aren’t careful enough. So, as state is a bomb, and we have to be careful of it, it would be better if we isolate it, so the rest of our code will be safe.

We can create a ViewModel. Or name it as you want. The purpose of a ViewModel is to store the state for our view, and encapsulate the logic of how to manipulate it. Our View won’t know how to operate on the operands anymore, nor know what is an operand, or which is the current operand. In our example, our view will:

1. Handle the user events, and notify the ViewModel.
2. Get data from the ViewModel and update accordingly whenever the data changes.

And the ViewModel will be responsible for:

1. Receive events from the view.
2. Expose data to the view and notify whenever the data changes.

This approach is a bit more complex, because we need to maintain two classes instead of one, but it has other benefits. We splitted the responsibilities, and we know that the ViewModel will always have the current state. There won’t be duplicated states, or inconsistent states on our view.

We’ll need a way to notify the view when the data changes in the ViewModel. We can use delegation, or configure a closure so we can execute it from the ViewModel when the data changes, but it’s better to use a specialized tool for this. Some people use RxSwift/RxCocoa, and I’m also a great enthusiast of these tools. However, Apple listened us and created a library that is included in the iOS SDK and does that for us: Combine. So we’ll use it on our example

In practice, this will be our ViewModel.

So, what’s happening here? Let’s go through it:

  1. In Combine, @Published variables are variables that are like any other variable, but they have a projectedValue (the $ prefix) that returns us the Publisher associated to it. And by using a Published we can operate on the changes the value can have over time. In our ViewModel we have input variables (the ones that our View Controller sets), and output variables (the variables our View Controller listens to).
  2. When we listen to a Publisher, that subscription needs to be managed in terms of memory usage. That’s what our array of AnyCancellables does. Apart from that, we can use this extension to make our code more elegant:
    https://gist.github.com/fmo91/91132290e687284468857589381eb8c6
  3. These are the listeners we can configure so our code is reactive.
    * Whenever the firstNumberText value changes, it’s converted into a Int, and finally it’s value is assigned to firstNumber. We do the same with secondNumberText and secondNumber.
    * Something similar is used to transform operation to operationText.
    * As we are making subscriptions, we need to manage the memory usage here appending them to our array of AnyCancellable objects.
  4. This is basically what calculateResult did in our previous example. We execute this whenever firstNumber, secondNumber, or operation change. And finally we assign the value to result.

On the other side, we need to update ViewController, the code is below, but the important thing to keep in mind here is that now our VIewController just updates values in the ViewModel and listens to changes on it. Nothing else.

Much simpler.

A bright future in the horizon

As you can guess. the above code is elegant and scalable. But it still looks unnatural. These are not how UIKit was build to be used. UIKit is imperative. And even the documentation Apple gives to us encourages us to work imperatively. This is embedded in the DNA of the framework.

But something is changing. The reactive/declarative approach for UI development and state management has gained great adoption during the last five years or so, mainly since React gained popularity and became the default way to build UIs in the web.

Apple also listened to this revolution taking place, and came out with a new shiny framework named SwiftUI. In SwiftUI we declare our state, and the view that is build using that state. Whenever the state changes, the view is configured again. Sounds familiar? It’s exactly the principle our ViewModel-based solution was built based on.

Even when SwiftUI is in its infancy, it’s a great tool we should keep an eye on it.

--

--