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.