State of the Art

As the U.S. barrels toward Election Day—one that feels, in a very real way, like it could be our last—I’ve tried to fill my fractured thoughts with pursuits that are alternately mindless or educational. Most recently, I've been building my own little reactive state manager using vanilla JavaScript to better understand how they work—and stumbled across a bit of a historical wormhole in the process.

Another State Manager?

The field of state management tools is crowded, to say the least, with well-known, well-tested libraries and frameworks written by scores of developers who actually know what they’re doing. So why build my own?

I’ve used both Vue and React in the past, but never stopped to consider what it would take to implement reactive state-based rendering. It has always felt a little magical, to be honest: update the value of a single property and watch changes cascade across an interface automatically (and predictably, which I love).

When the complexity of a small side project outgrew one-off functions and application state defined in DOM element attributes and values, it felt like a good opportunity to pull over and finally try building a manager myself. Since my goal was to better understand the mechanics of implementing reactive state rendering, rather than to enter my rookie contender into the public fray, I wasn't shy about borrowing from the vernacular of Vue and friends.

This is where I landed:

let game = new State({
    data: {
        letters: ["a","d","i","n","o","p","r"],
        requiredLetter: "a",
        solutions: {
            draft: [],
            accepted: []
        },
    },

    computed: {
        score()
        {
            // 4-letter words are worth 1 point; (n > 4)-letter words are worth n points
            return this.solutions.accepted.reduce( (total, word) =>
            {
                return total + word.length < 5 ? 1 : word.length;
            }, 0 );
        },
    },

    render() {
        // ...
    }
});

If you're not familiar with this pattern, the data option object passed to the State class constructor defines static properties that can be read or written by the containing application. These are made available via the State instance's data object:

Animated illustration showing the result of setting a static data property

Similarly, the computed constructor option is an object that defines dynamic properties whose values are crunched and returned by functions. They are accessed via getter and setter shims on State.data, right alongside their static cousins:

Animated illustration showing a computed property automatically updating as a result lf setting a static property

Finally, whenever the value of a property on State.data is set the manager invokes the user-provided render option, a callback responsible for ensuring that the relevant UI bits accurately reflect values defined in state. When invoked, the callback has its this context set to a read-only clone of State.data, giving the renderer direct access to the current snapshot of state at that moment in time.

None of this is groundbreaking or innovative, of course, but dang does it feel great to pop into developer tools, update a single value, and see the results spring to life:

Animated illustration showing setting a static data property resulting in UI updating automatically

just like in the big leagues.

Illuminating the Past

Around the time I rolled up my sleeves on this little research project, I was just starting to work my way through Articles of Interest, a podcast mini-series about clothes, fashion, and other things we wear.

Episode 1 introduces us to the Jacquard machine, a loom peripheral of sorts invented in the early 1800s that brought automation to the art of weaving and textile manufacturing. Here's a peek at one in action:

While my brain was background-processing some ideas about state management improvements I was working through at the time, a single line in the episode caught my full attention:

One card represented just one pass of thread.

At any given moment in a state-based renderer—whether that’s Vue, React, or even my little research project—the State.data equivalent is a collection of values describing how to produce a precise, predetermined pattern.

If we dial down the resolution on our state data (and suspend quite a bit of disbelief for the sake of artistic interpretation):

Animated illustration showing a series of dots drawn to resemble the layout of the game state JavaScript object

it's not too much of a stretch to see something familiar looking back at us across the great span of technology:

Animated illustration suggesting a visual parallel between the game state JavaScript object and Jacquard loom cards

Set. Render. Set. Render. And on and on.

Contrived visual skullduggery aside, it’s not wholly unlike advancing the next card into a Jacquard machine, then sending the shuttle on a pass through the loom to bring our pattern to life.

As Christine Jeryan and Avery Trufelman both reminded us, we can draw a rather direct line from computers as we think of them now, through punch cards, all the way to their textile ancestors. But I think it’s also comforting to know we don’t have to look far to find living fossils in the contemporary development tools and design patterns of today.