State Driven Development - The Beauty of Enums in Swift

Last updated: 8 months ago

State Driven Development

A lot of people discover enums pretty quickly when exposed to Swift. They're arguably one of the most powerful swift language features. Many of us have probably used enums in other programming languages too. Sometimes we might be using enums without even realizing it.

But I think that enums are so valuable that they're worth designing software around, similar to object oriented programming or protocol oriented programming.

It's what I think of as State Driven Development, and that's what this talk is really all about.

Enums make invalid states impossible to represent. We're all used to using boolean state variables to represent the states that our objects can be in. But many times, the combinations of different boolean values represent states that we don't expect or shouldn't allow. Using enums to define specific states makes these invalid combinations of boolean values impossible to represent in our code, which in turn makes several types of bugs impossible to write. That's a big part of why we like building apps in a strongly typed language like Swift in the first place.

Enums help us be specific about the state of an object. That's really what state driven development is all about. They're useful not just for model objects and types, but for views and interface flows as well. Any piece of state in a Swift application can be represented by an enum case, which becomes a wonderful way to build applications.

Enums can also be extended with variables and functions. Whenever you start to check the state of an enum, ask yourself if that check could be a variable or method that gets defined on your enum itself. That way, we ask our enum to describe behaviors for us, and then use its cases to implement those behaviors for the possible states we want to handle.

The state driven development pattern is incredibly helpful when it comes time to add new behavior to an existing class. All you need to do to add new behavior is add a new case to your enum, and add implementations to all of your methods specifically to handle that case. The methods that are part of your enum are effectively the public API to extending the behavior of your object!

Instead of:

var hasLoggedIn : Bool = false

var workoutInProgress : Bool = false

var savingWorkout : Bool = false

func startWorkout() {

guard hasLoggedIn && workoutInProgress == false && !savingWorkout else {
    return
}

workoutInProgress = true

}

We are aiming for:

enum WorkoutApplicationLifecycle {

case notLoggedIn
case workoutInProgress(current : Workout)
case savingLastWorkout
case readyToStart

var canStartWorkout : Bool {
    get {
        switch self {
        case .notLoggedIn: fallthrough
        case .workoutInProgress: fallthrough
        case .savingLastWorkout:
            return false
        case .readyToStart:
            return true
        }
    }
}

Associated values also greatly expand the types of questions that your enum can answer inside your application's components. If you have an object that always needs to be associated with a specific case, like the specific workout that is in progress, you can associate it with that case on your enum.

In the above example, it makes a lot of sense to have the current workout live within the workoutInProgress case. You can access the associated value and pass that workout to your save workout method so that you know which workout you're saving.

Conversely, if I had a current workout property on my view controller, that property would really only make sense in one particular state that my app is in. In every other state, that value should be empty and thus it has no meaning.

Enums also help manage complex state for view controllers. For something like a document based view controller, there are usually several "modes" that the view controller can be in, like viewing or editing a document. The view controller has a lot of decisions to make based on the state it is in. Encapsulating that logic in an enum gives you a single place to reason about the logic for how to handle each state the document can be in.

There are lots of other great things about enums that make them a joy to use in Swift. I hope to enumerate all of the great things about enums and how they can improve our development experience in this talk.

Comments

UIKonf Friendly Commenter
3d25becddd50f5
8 months

Totally cool topic! Enums are so powerful and versatile in Swift 🎉

UIKonf Friendly Commenter
e542ed3c7d5571
8 months

Once the practical benefits have been demonstrated it might be a good opportunity to tell the audience they now know what a "sum type" is, therefore demonstrating type theory is not entirely abstract :)

Log in to comment