One question, multiple answers
What State is your app in? As our client, that question might mean something different to you than it does to us. For you, it may mean how close to release you are, or what your app looks like compared to your competition.
When we think of State, we think of the number of decisions that the app is making at any given time. Is the user logged in or not? Is the device connected to the internet? What search parameters have been typed in?
Each of these questions – and hundreds of others – all contribute to what software developers refer to as State: The combination of factors that describe a point in time in the running of your app.
A turnstile app example
Consider the diagram below. This diagram describes the operation of a pay turnstile.
There are two states in this diagram: Locked and Unlocked. There are also two Actions: Coin and Push.
If we were creating an app based on this diagram, We’d have to do write some code. We could start by writing code that allows you to perform Actions:
1) We’d have to write some code (and some type of buttons) to allow you to push the turnstile.
2) We’d have to write some code (with some more buttons) to allow you to ‘insert a coin’.
That’s lovely, but these actions aren’t very useful on their own! If a bit of code is run that performs an action, there needs to be some kind of result. The accumulated results of our actions are what we refer to as state.
So let’s write some more code that takes our actions and gives them context:
1) We’d have to write some code (and the visual representation) that shows you the results of a push on the turnstile when it is in the locked state.
2) We’d have to write some code (plus the visuals) that show you the results of a push on the turnstile when it is unlocked.
3) We’d have to write code (+visuals) that show what it looks like when we add a coin in the locked state.
4) And finally, We’d have to code up a representation of what things would look like if you added a coin when the turnstile was unlocked.
Whew! That’s a lot of things to code up. Notice that it’s more complicated to deal with the consequences of the actions than to create the actions themselves.
Imagine that we found that a significant number of people had found a way to cheat the turnstile, and get through without paying by shoving it. How would we represent that in the app?
We have to add a new state. We’ll call it “Tilt”. Below is the updated diagram.
It’s clear to see that the app is now more complex than before. But by how much? We’ve added one new state. What does that mean in terms of new code paths we need to add?
1) We need one action to ‘Shove’ the machine.
2) We need another to ‘Return’ it to its starting position.
1) Shoved the machine in the ‘Locked’ state (moving to the ‘Tilt’ state).
2) Returned the machine to the ‘Locked’ state
3) Shoved the machine in the ‘Unlocked’ state
4) Returning the machine to the ‘Unlocked’ state
5) Shoving the machine while already in the ‘Tilt’ state
By adding one state to our app, we’ve more than doubled the number of things we worry about in the code.
One of the classic examples of reducing state is the iPhone. The original iPhone, while clearly revolutionary, was disappointing to many people for lacking what seemed like standard features in other phones, such as:
1) a replaceable battery
2) 3G data connection
3) User downloadable apps
Steve Jobs was a ruthless feature-cutter. If a feature couldn’t fit seamlessly into the overall vision, it was removed. If a feature didn’t perform as desired, it was removed. Even if the entire world was clamoring for that feature, Apple remained resolute.
This drastic feature reduction allowed for Apple’s support to become much simpler. Apple support staff had a guide for almost every situation the phone could be in. For every question, there was an answer. This led to faster support, and happier customers. This also led to the iPhone’s reputation as a rock-solid device.
How we can help
At Push Interactions, we can help you reduce the amount of state in your app and develop a rock-solid product for your users. We do this in a number of ways:
At Push, every project starts with us talking to you about your vision. We listen to everything you tell us, and identify the main problems that the app needs to solve. From there, we work together to come up with a design that captures the features that are truly needed, and to eliminate features that will add needless complexity. We’ve become very good at this step, and it’s something we’ve become very proud of.
Our developers deal with the trade off between complexity and functionality every day. As a result, they have collected a number of tricks that can manage state in a complex app. For instance, when we code, we write tests in the code that capture the functionality of the app as we go. These tests ensure that the the code is always doing what we think it is. If we change something later on in another part of the code, we will always run the tests to ensure that what we finished previously was not broken by the change.
In addition, we employ a rigorous code review process that ensures that every feature we build into your app is reviewed by at least two developers and our Quality Assurance team.
Sometimes we can’t mitigate or remove state. This makes sense, because without state, the app wouldn’t be able to do anything! We understand that state is always going to exist, so after we minimize the amount of state in the app, we then must manage it appropriately. We employ a ‘layered’ architecture, that allows us to keep the state of your app harnessed in one place in the code. That way, when you want to make a change or add something later, we can do it with a minimum of hassle and expense.