Ruby on Ales 2016
A Machine State of Mind
Summarized using AI

A Machine State of Mind

by Vaidehi Joshi

In the talk titled 'A Machine State of Mind,' Vaidehi Joshi discusses the complexities of managing mutable state in software development, emphasizing the significance of state machines as a solution. The presentation unfolds the concept of state machines, which are often perceived as intricate, and breaks them down into manageable components. Joshi encourages developers, regardless of their experience level, to approach daunting concepts like state management with self-compassion and a willingness to simplify.

Key points discussed include:

  • Understanding Mutable State: Joshi highlights that the challenge of handling mutable state is a frequent struggle among developers, often leading to feelings of confusion and frustration.
  • Introduction to State Machines: State machines are introduced as flowcharts that manage the transitions and rules governing state changes, making complex logic easier to handle.
  • Core Components of State Machines: There are four critical elements within state machines:
    • Actions (functions that need to occur)
    • Events (triggers for those functions)
    • States (data tracking the functions)
    • Transitions (logic for moving between states)
  • Indicators for State Machine Usage: Situations such as having a database column for state, methods returning boolean values, or managing time-sensitive records suggest the need for state machines.
  • E-commerce Example: Joshi uses an e-commerce application to illustrate how state machines can represent order lifecycles, transitioning through various states from 'unplaced' to 'shipped.' This example simplifies the understanding of state machines by visualizing their functional flows.
  • Tools for Implementation: The talk introduces the 'AASM' (Acts As State Machine) gem, which simplifies the coding of state machines. By declaring states and defining transitions, developers can generate robust state management logic without overwhelming complexity.
  • Self-Referential Machines: Advanced state machines can refer back to their states, allowing for nuanced behavior like conditionally checking states before executing functions.
  • Learning and Adaptation: Joshi stresses that learning new concepts takes patience, and breaking down complexity into digestible parts can increase confidence in tackling new challenges.

In conclusion, the key takeaway from Joshi's presentation is that state machines provide developers with a powerful framework to manage mutable state effectively. By approaching complex topics like state management with compassion and simplification, developers can not only improve their coding practices but also enhance their overall problem-solving skills in software development.

00:00:13.460 So just to get a feel for this room, how many of you have been programming for less than two years? How about less than five years? Less than ten years? More than ten years? Okay, we have quite a mix of experience levels. And in this room, how many of you at some point in your programming careers have felt like this, where you don't really know what's going on?
00:00:37.550 Most of the time when I’m sitting in front of a computer, I have no idea what I’m doing. It’s not like I’m completely new, but it happens frequently. And I think that’s okay. Hi, my name is Vaidehi Joshi. You can find me most places on the internet at Vaidehi Joshi. I’ve come to realize that whether you’ve been programming for six weeks, six years, sixteen, or even twenty, there are times when you may feel completely out of your depth. It’s totally normal to not know what you’re doing, especially since what we do for a living involves solving incredibly tough problems. A lot of what we do involves trying to mirror complex, real-world objects in software, and that process is often anything but simple.
00:01:58.450 Things never start or end the way we plan for them to, and specifications change. You might start off wanting to build something that ends up looking really different from what you finally create. This theme ties into many of the talks we've been hearing yesterday and today: the endless stream of learning that we are all navigating as we tackle things we’ve never done before. I hope that by the end of this talk, I can share something I learned—something that was among the scariest concepts I encountered—and how I overcame my fear of it. I really hope that when I move to the next slide, no one runs out of the room, because that would be quite sad.
00:02:55.530 At my very first development job, one of the hardest things I struggled to learn was the daunting concept of state. I had no idea how to manage it, and I find that application state and the state of an object can be incredibly difficult to grasp, especially for someone like me who doesn’t have a computer science background. I’ve only been programming for about two years, and before entering the software field, I was a sixth-grade teacher and a freelance writer. It was quite a surprise when I was faced with terms and concepts that I didn’t understand at all.
00:03:55.900 Part of learning something new is being compassionate towards yourself and accepting that big, scary concepts can often be less intimidating if you can break them down into simpler pieces. At the end of the day, everything is just part of something larger. State machines were one of the ways I learned about handling state. When someone introduced me to state machines, I looked it up in our source code, but I didn’t really know what that meant. So, like many of you might have done, I turned to the Internet for help. However, it wasn’t particularly helpful; I ended up confused by terms like finite state machines and directed graphs. This left me feeling lost.
00:05:10.090 Instead of being frustrated by that, I decided to try to break down the concept of state machines. I ended up learning how cool they are and how they can be utilized to solve complex problems related to mutable state. Essentially, I learned that state machines are just flowcharts. If we start thinking of something complex as a set of simple parts, it becomes far more approachable. If we consider a state machine as just a flowchart, it’s easier to break it down into different parts and understand how everything works—that is, how flowcharts control the sequence of operations.
00:06:30.300 There are four fundamental components to any state machine, regardless of its complexity: First, you have actions, or functions, that need to occur. Second, there are events that trigger those functions—essentially the reasons for calling them. Third, you need some sort of data to track the functions and their conditions; these are your states. Finally, you also need to implement some complex logic that manages transitions between states or events, which is incorporated in the code. Sometimes, it might feel like a lot is happening within a state machine, which can be daunting. However, there are indicators for when you might want to utilize a state machine.
00:08:59.640 For instance, if you have a database column called state or status, that could signal a need for a state machine, as such scenarios can become complex quickly. Another indicator could be instances where methods return boolean values or if there are timestamps with null values to manage. If you have records that are valid during a certain timeframe—like with a start date and end date—it may be helpful to consider implementing a state machine. Code that resembles complex state handling logic could benefit greatly from being restructured into a state machine.
00:11:38.870 Before diving into writing a state machine, it’s beneficial to clearly understand the goal. One method I find helpful is sketching out what I want to build. For example, let’s say we have an e-commerce application, and we want to represent a piece of state on an order object. We can outline the lifecycle of an order, noting that they typically start in an unplaced state, move to a submitted state, and then progress through processing, shipping, and delivery states. To find the four components of a state machine for our order object, we will mark input functions for user action—like entering a credit card number to transition from unplaced to submitted. Events can be when a user successfully submits their form; this ties back to the state machine events we discussed.
00:13:53.670 We also need states to track where our order is in its lifecycle. An order in its processing state will encapsulate all activities related to fulfilling, packaging, and shipping the order, along with all requisite functionality. The main point is to enforce rules so that certain actions cannot happen unless specified conditions are met. If we think back to our sketch, we may find the state machine has some unidirectional flow, but in practice, things can be more complex. For instance, a completed order might revert back to processing if a user realizes they ordered the wrong size and wishes to return it.
00:15:05.740 Fortunately, we can design our state machine to handle increased complexity as needed. If our state machine becomes self-referential, it can utilize features like directed acyclic graphs (DAGs). This self-reference allows the state machine to reflect on its own states and make transitions based on those reflections. This is a powerful capability that enables the creation of sophisticated state machines that will facilitate the handling of your complex logic.
00:16:11.660 Now, when it comes to coding this, there are several gems available that simplify implementing state machines, my favorite being the 'AASM' (Acts As State Machine). To get started, you simply include it in the model you want to track. You need an initial state, and all state machines begin with one. After that, defining how one state transitions to another is straightforward, especially since this is often about wiring up events.
00:17:10.770 In its simplest form, a state machine might look like this: you create an order with an initial state of 'unplaced,' and you can transition to a 'submitted' state through a specific event being triggered. Yet again, things can rarely be that simple. As we add more states, such as 'processing' and 'shipped,' we create pathways for complex transitions. It’s important to note that users may want the option to return orders, adding further states that our machine must accommodate. Therefore, a well-designed state machine can become self-referential, facilitating more complex transitions.
00:18:20.830 As you write your state machine, you gain the ability to transition between multiple states while reflecting upon previous states in your logic. This capability allows for intricate functionalities—like checking whether an order is unplaced and whether you can submit it or execute specific events based on current states. Interestingly, although we did not explicitly write those methods, they are generated dynamically by the AASM based on the states we define in our state machine.
00:19:24.720 This feature of AASM means that you get many transition and state-checking methods for free—like ensuring proper state transitions. But it’s also essential to recognize how complicating it can become without a state machine. If you were to implement an unplaced state from scratch, you would face a labyrinth of migrations, methods, and various states that require careful handling, meaning the potential for bugs and oversights rises steeply.
00:20:54.820 Moreover, state machines provide opportunities for adding additional functionality, like passing blocks to events where the code within only executes if the transition succeeds. This means you can create side effects only in response to successful state transitions. You can also use callbacks to hook into the lifecycle of your state machine, executing specific code when entering or exiting states—making it easier to manage complex behaviors.
00:23:00.580 I think many people find concepts like state machines intimidating because they can feel overly complex or abstract. However, it’s essential to recognize that regardless of your experience level, learning new concepts can be daunting. Yet with a little self-compassion and patience, we can simplify these intimidating topics into manageable pieces. Ultimately, this process of learning and breaking things down can be enjoyable, as experimenting with new ideas fosters growth and exploration. The nature of our work as developers and lifelong learners makes it one of the most fascinating jobs out there. Thank you.
Explore all talks recorded at Ruby on Ales 2016
+2