Swizec Teller - a geek with a hatswizec.com

Senior Mindset Book

Get promoted, earn a bigger salary, work for top companies

Senior Engineer Mindset cover
Learn more

    A new VSCode extension makes state machines shine on a team

    When you grok state machines, a new world of computational beauty and software design opens in front of your eyes. Things that used to be hard become easy. The impossible becomes possible. And you turn into that annoying team member.

    "Damn it! Stop it with these state machines. Nobody understands your code"

    It's true, nobody understands what the heck this means:

    const loader = createMachine({
    id: "loader",
    initial: "fetching",
    states: {
    fetching: { on: { FETCHED: "fetched", ERROR: "error" } },
    fetched: { on: { RELOAD: "fetching" } },
    error: { on: { RETRY: "fetching" } },
    },
    });

    But if you show it like this:

    Loader state machine in Statelyai's VSCode plugin

    Now we're talking! This is a smol state machine that represents a data loader with 3 states – fetching, fetched, error – and transitions between them.

    That's all a state machine is – a collection of states with transitions. Best represented as a state chart like above, easily drawn by hand, popular building blocks for complex systems based on the actor model of computation.

    You can think of ant colonies, human cities, and generative video game landscapes as examples of actor-based computation with state machines. An exploration for another day :)

    You're already building implicit state machines

    The one thing you should take away from this article is that you are building state machines even if you don't realize it. State machines are everywhere.

    Take this (pseudocode) React component for example.

    It uses React Query to load some data, a showMore state to choose how big a list to render, and attempts to handle various edge cases.

    function pseudoCodeExample() {
    const { data, isLoading, isError } = useQuery();
    const [showMore, setShowMore] = useState(false);
    function onShowMore() {
    setShowMore(true);
    }
    function onHideMore() {
    setShowMore(false);
    }
    return (
    <div>
    {isLoading && <Spinner />}
    {!isLoading && !data && <NotFound />}
    {!isLoading && isError && <Ooopsies />}
    {!isLoading && data && (
    <>
    <List data={data} count={10} />
    {!showMore && <Button onClick={onShowMore} />}
    </>
    )}
    {!isLoading && data && showMore && (
    <>
    <List data={data} count={data.length} />
    <Button onClick={onHideMore} />
    </>
    )}
    </div>
    );
    }

    You can imagine how a component like this grows over time. The bugs were whack-a-mole, new exceptions and edge cases were added, and nobody took the time to step back and think "Is our approach wrong?"

    Can you spot the bug? Revealed at the bottom.

    Complex conditionals like that break my brain and When your brain is breaking, try XState ✌️

    Explicit state machines feel like more work

    Adding an XState state machine to that component feels like extra work.

    The state machine itself is not simple:

    const stateMachine = createMachine({
    id: "machine",
    initial: "loading",
    states: {
    loading: {
    on: { ERROR: "error", LOADED: "loaded" },
    },
    error: {},
    loaded: {
    on: { SHOW_LESS: "show_less", NOT_FOUND: "not_found" },
    },
    show_less: {
    on: { SHOW_MORE: "show_more" },
    },
    show_more: {
    on: { SHOW_LESS: "show_less" },
    },
    not_found: {},
    },
    });

    And then you have to write all the glue code to drive this state machine. React Query and XState don't natively talk to each other. Yet 🤞

    Jim Bolla avatarJim Bolla@jimbolla
    @Swizec Is this the tweet that leads to a version of #ReactQuery based on #XState? Pls say yes.

    Rumor has it David and the Stately.ai team are working on a plugin system for XState.

    But look what happens to our rendering logic:

    switch (state.value) {
    case "loading":
    return <Spinner />;
    case "not_found":
    return <NotFound />;
    case "error":
    return <Ooopsies />;
    case "show_less":
    return (
    <>
    <List data={data} count={10} />
    <Button onClick={showMore} />
    </>
    );
    case "show_more":
    return (
    <>
    <List data={data} count={data.length} />
    <Button onClick={showLess} />
    </>
    );
    default:
    return <Spinner />;
    }

    Feels much more readable to me. You see all the states and what they render. Add TypeScript and you'll know at a glance if anything is missing.

    And we fixed the bug 😉

    Statelyai's VSCode extension 😍

    Where state machines shine is visualizing your logic. Reading the original soup of conditionals is hard because you have to picture what's going on in your brain.

    That's where the "OMG Don't distract me!" meme about programmers comes in. Holding glass palaces of complexity in your brain is hard. Let the computer do it!

    Install the xstate-vscode extension and you get this 👇

    xstate-vscode extension in your editor
    xstate-vscode extension in your editor

    Open the inspector and look at this. Right in your editor!

    Visualized state machine in VSCode
    Visualized state machine in VSCode

    You can click around to simulate events and see what happens. There's a lot of dead ends in our state machine. Users could get stuck 🤔

    Editing state machines visually 🤯

    The UX of our example component is terrible. All those dead-end states means users can get stuck. Why is there no retry on error? What about not found? What if you want fresh data after reading for a while?

    xstate-vscode comes with an editor! It's a little buggy right now and doesn't support everything XState can do, but it's wonderful for fixing issues like this.

    Visually editing state machines in VSCode

    That looks messy I agree. The visualizer is wonderful though.

    The final state machine neatly laid out
    The final state machine neatly laid out

    Next time you're dealing with complex UI logic, consider employing a state machine. With Statelyai's new XState VSCode extension, they even shine on a team.

    Cheers,
    ~Swizec

    PS: the bug in my first component is that <List /> renders twice when showMore = true. Users will see the first 10 elements twice

    PPS: for an example of refactoring useReducer to XState, try this series of articles

    Did you enjoy this article?

    Published on February 25th, 2022 in Uncategorized,

    Senior Mindset Book

    Get promoted, earn a bigger salary, work for top companies

    Learn more

    Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.

    Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.

    Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help 👉 swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.

    Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers 👉 ServerlessHandbook.dev

    Want to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz React components your whole team can understand with React for Data Visualization

    Want to get my best emails on JavaScript, React, Serverless, Fullstack Web, or Indie Hacking? Check out swizec.com/collections

    Want to brush up on modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com

    Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog

    Want to brush up on your modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com

    By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️

    Created by Swizec with ❤️