Remote Ruby

Unlocking the Power of State Machines in Code Development with Elise Schaefer

December 01, 2023 Jason Charnes, Chris Oliver, Andrew Mason
Remote Ruby
Unlocking the Power of State Machines in Code Development with Elise Schaefer
Show Notes Transcript Chapter Markers

Welcome to a lively conversation where we turn the spotlight on the oft-overlooked powerhouse of web development - state machines. We'll share our insights, experiences, and the reasons why we think state machines are the secret sauce to simplifying complex logic. If you've ever felt bogged down by the complexity of transitioning systems between states, you're in for a treat as we illustrate how state machines can be your knight in shining armor in the realm of code development and maintainability.

We're thrilled to welcome Elise Schaefer, our new podcast host, who has stepped into her role with immense enthusiasm and a deep passion for Ruby. She brings with her a fresh perspective and an eagerness to shape engaging conversations with members of the Ruby community. As she doffs her hat to the well-structured platform left behind by Brittany Martin, Elise also shares how she's tweaking it to align with her style. 

So, what's the magic formula to recognize the need for a state machine? We believe the answer lies in the presence of state in a database column or the use of enums. Listen as we traverse through the use of timestamps and callbacks in state machines and how they capture crucial nuances in the code. We also share our excitement on the immense potential of future changes in languages and how this could revolutionize web development. So, buckle up and join us on this exciting adventure as we unravel the power of state machines and the future of programming.

Honeybadger
Honeybadger is an application health monitoring tool built by developers for developers.

Disclaimer: This post contains affiliate links. If you make a purchase, I may receive a commission at no extra cost to you.

Speaker 2:

This is remote, have you any remote ideas to the meaning of the word.

Speaker 3:

Andrew couldn't last, I lost it.

Speaker 1:

I have talked to you more today than I have, and we're more this week than I have in a while.

Speaker 3:

Maybe even when we were in Amsterdam together every day, like every minute.

Speaker 1:

Well, conferences these days are a little hard for me. Now I need to get the DHH hoodie and go hide in a corner at some point.

Speaker 3:

Well, I'm excited for this episode because, as you might have recently learned, the Ruby on Rails podcast has passed the baton. Brittany Martin, who was the Ruby on Rails podcast host and a really good friend to all of us here at Remote Ruby decided to enter a new step of her life and today we have the person taking the baton from her, so I would like to welcome Elise Schaefer.

Speaker 2:

Thanks for having me. I'm very excited to be here.

Speaker 3:

Well, really grateful that you joined us today. Elise actually reached out to us. I just thought that was really cool, because one thing that's really cool about Ruby podcasting is, historically, I mean, hasn't felt like us against someone else. It's always just been like a bunch of people with different takes lifting up the same community. So cool to keep that going and excited to get to know you and along those lines, would love to maybe give you a moment to introduce yourself and, yeah, maybe just kind of how you got into Ruby and into hosting the Ruby on Rails podcast.

Speaker 2:

Sure, so my name is Elise Schaefer. I've been doing software development professionally since 2010. I've been using Ruby for pretty much that entire time. I started out as kind of working in like a government consulting type deal and the work that I was doing was kind of like application development for government agencies right to do like permit tracking and stuff like that Not super complicated stuff but it's like governed by a big regulations and so the regulations make it more complicated than maybe it needs to be. But that's where I learned Ruby. That's where I learned Ruby and I learned Rails and I sort of fell in love with it.

Speaker 2:

I have a traditional computer science background so I grew up with computers and so that part of my story is kind of boring. It's the route that you would assume someone has, so that part of it's a little bit boring. But I fell in love with Ruby, the first language that I learned, where I felt like I could guess method signatures. I could just guess them and I'd be right about 80 or 90% of the time and when I was wrong I could like change the argument order and that probably be right. So that's kind of my career. I've worked in a lot of different industries I've worked in consumer electronics, I've worked in billing, I've worked in cybersecurity, that kind of stuff across the gamut a little bit. So that's like kind of the story of my career trajectory and I'm happy to dive into any of that. That's like interesting.

Speaker 2:

The story of taking over the podcast is really kind of serendipitous and it's sort of like I had helped to organize a panel at RubyConf RubyConf mini last year, and that had kind of introduced me to some people and so Brittany was there for that panel and she saw that panel and then when she was looking for a new host, I believe Jemma had maybe mentioned my name. But after that panel I had stepped kind of not on purpose, but I'd sort of stepped back from the community a little bit. At the time I was like going to take a break and then I became a manager and sort of things happen. So at the time that Brittany reached out I was sort of looking for a way to kind of get back into the community and do something for the community. And it's sort of a situation of like the universe just drops something that you've been looking for on your lap. And that is sort of how it happened.

Speaker 2:

Brittany reached out. She said, if you're interested in this, like, let's set up a time to chat. We set up a time. We got on a call and I was super excited about doing it. If there's a community that is probably going to be the most fun to interview people, it's probably the Ruby community. I feel like there's a lot of cool people who are working on cool things and who have good stories. And then so we had a couple of conversations. I met kind of the other people involved in the show. We went on from there. We organized the episode where she kind of handed over the baton to me and then I took over and I've been running with it since for the last few episodes.

Speaker 3:

That's awesome. How has taking over been? Is this your first like podcast hosting experience, sort of?

Speaker 2:

So I did a limited run podcast thing for a conference that I had been so when I lived in Pittsburgh, there was an organization there called Pittsburgh Code and Supply and they organized a conference called Abstractions and as part of that at the time I was like involved in Code and Supply because I lived in Pittsburgh, and in the lead up to that conference we did some interviews with people who were going to be speaking, sort of to do like promo for it on YouTube. So I did a couple of those episodes where I did those interviews and that was like sort of podcast like. But it wasn't like a long term situation, it was like I don't know six or seven episodes or something. But this is the first time that I've taken on sort of a full time podcast situation. Yeah, how's the?

Speaker 3:

adjustment been Pretty good.

Speaker 2:

I think one of the nice things is that Brittany kind of had a lot of things figured out, so I sort of feel like I picked it up and I'm just rolling with it. I think there are some things that are still learning adjustments, but I feel like every episode I get more comfortable behind the mic, I get more fluid in the transitions and talking with people and I feel like it's coming more naturally every time I record, which is good. I think. Organization wise, I'm using like I've made some adjustments to the template and the script and stuff just to sort of match my style a little bit better, but it's been easier than I thought it would be. To be honest, I was like a little bit more scared and it turned out to be very kind of, mostly good. Like, once you actually start recording and you've done it a couple of times you just sort of fall into a flow, I feel like. So it's been easier than I thought it would be for sure. Yeah, that's good.

Speaker 1:

We did it the hard way, with no plans, no nothing, no editing, and we just like.

Speaker 3:

No scripts no.

Speaker 1:

But I think we've, over time, ended up with those same sort of systems that really make it kind of, yeah, we sit down, we jump on Zoom, we talk a little bit ahead of time and then you know how to kind of guide the conversation when one topic's over, it's time to switch things or whatever. And those are great if you've got the systems, or like here's a bunch of gotchas that you wouldn't expect, until you're in the middle of recording an episode and you probably had the shortcut on all that, which is good. Yeah, I was just going to say it's really cool To see like a podcast like that doesn't die and it has sort of this process of transitioning hosts where it's like no one wants this to go away, but everybody has different phases of their lives. So it's your turn now, which is such a cool thing, because I have a feeling most podcasts never really make it to that next step if one of the core people steps out.

Speaker 2:

Yeah, kind of feels like, oh, I'm the shepherd of the podcast Right now. Brittany was the shepherd of it before and she really revived it. I mean, the podcast was pretty much dead when she took it over, so I feel a certain amount of responsibility to that and maintaining the audience. But I also know that at some point in the future there's going to come a time when it's time for me to pass the baton to someone else and, keeping that in mind too, that it's more of a community institution like even like my institution me taking over the podcast. I have my own style for how I do it, but I think that's important to keep in mind too and I try to keep that at the forefront.

Speaker 3:

I really like that perspective on it. It has carried on for so many years.

Speaker 1:

It's got a legacy.

Speaker 3:

Legacy yeah.

Speaker 1:

Yeah, it's cool, but it makes me think about open source projects that you maintain, or our podcast or I don't know anything. Really, it's like how do you make something that sustains the individual who might have pioneered it? But this is important for the community, and when core podcasts disappear in a community, that's not a good sign for people who are just joining and looking for jobs and whatever. And it's amazing to see this transition, which is kind of rare, it feels like, but also very welcomed. I just wanted to. I feel like it was just such a good thing to happen.

Speaker 3:

So I would be interested in jumping back a little bit, because you mentioned like you were doing government work when you learned Ruby, and then you went on to mention like consumer electronics and cybersecurity and things like that, and I'm interested to know if you were using Ruby in any of those roles.

Speaker 2:

Yes, I mean Ruby has been kind of a through line throughout my career actually. I mean I've done some like tangential stuff off of it. I think consumer electronics is maybe one that's like a little bit. You'd be like, oh, what would you use Ruby for? So in that one it's mostly was embedded C, so it's like writing C on a microcontroller. But when you're doing electronics manufacturing you have to test all of the chips that are printed. You have to test the circuit boards and everything. So those test fixtures you built a test fixture that clamps onto the board and has connections that is to talk to a computer, all of the stuff on the computer that was doing all of the testing of those boards and then printing reports on defect rates and all of that stuff. That stuff was all written in Ruby on a regular laptop using just Ruby, gtk or whatever. So that was interesting and cool.

Speaker 2:

I think a lot of people think of Ruby and the first thing they think of is Rails. But Ruby is useful for so many things. I think all it takes is just to see it in a different light and that can help you understand the language better and understand your tools better, and that's true of the other roles that I've had too when I was working in. This is. My most recent role was with a cybersecurity firm and they build a platform for security for other businesses so you can use them to be your security provider, and they have a platform that ingests from a bunch of data from sensors on laptops and stuff, and then they analyze that data. All of that stuff was written. Well, most of it was written in Ruby, then a Rails front end, obviously. I think it's a wide gamut of things you can do with Ruby.

Speaker 1:

Yeah, I was going to say I remember when I was getting into Ruby in college I loved application security stuff and was going to go into security. But then I realized to be really good at app security you really need to know how to write applications so you can figure out where things go wrong. But at the time I didn't know anything about Ruby, except for Metasploit was written in Ruby and it was the maybe still is, I don't know one of the biggest projects in Ruby period and that's used everywhere in security testing and stuff. So it's kind of the testament to the Ruby.

Speaker 1:

Language is one design for humans first, which is why I love Ruby, because it's like you can get an idea from your head. You're thinking in the words that you speak, you're not thinking in binary, so you can translate an idea into code a lot faster than having to deal with the syntax of C++, memory allocation and all these other things, especially with things like active support. A lot of times you're just writing English that happens to read just like your thoughts would read, or if you were to write it out in a spec sheet or something. I think that's the magic that I really like about Ruby. It can apply to anything.

Speaker 2:

Yeah, one of the things that's interesting that you were talking about just sparked a thought which is even like it being built for developer. Happiness is such an important part, even parts of the syntax that seem weird when you're coming from another language, like the dot each do right. That seems very weird if you're used to like for X in set.

Speaker 1:

Yeah, or I equals, zero plus plus Right. Yeah, yeah.

Speaker 2:

But, like to me, that makes so much sense. It makes so much more sense to say here's an array, like each item in the array, do this thing right. That makes so much more sense to me.

Speaker 1:

Yeah, my first time I saw like 100 dot times do this and I was like, yeah, oh my God, like it just reads like English. It's amazing.

Speaker 2:

Get the feel of like it's almost like magic, right when it works, and you're like I didn't expect that to work. But maybe I should have expected it to work because like, yeah, that's like what I meant, right, Like yeah, that's such a wild thing that you'll never experience that in almost any other language.

Speaker 1:

Because, like you said earlier, you can be writing code and you're like surely there's not a whatever helper or method or something.

Speaker 1:

And then you're like, but I'm going to try and it's like, hey, this returned a range of all the days in the month.

Speaker 1:

That's nuts that someone already thought of this and built it and I can just like skip all of that logic of like I'm building a calendar and I need to know the current day and then go back to the beginning of the month, which might be any day of the week, and then maybe you need to still go to the beginning of the week because the beginning of the month is on Friday and you got to render a calendar that's actually like a rectangle and like those little things are like super easy in Ruby often and you're like what, this is crazy. So, yeah, I definitely can relate to that, which kind of I feel like we were talking before. This episode kind of leads us into talking about state machines, because we were talking about ideas to talk about on this episode and started going down the rabbit hole of like state machine gems Don't quite have the right feel. Yet I feel like I think you definitely have a lot to say on this.

Speaker 2:

Yeah, this is a bugbear for me. I'll take it in sort of two parts. The first one is state machines and sort of an argument to convince listeners and everyone in the industry that they should use a state machine. State machines are. I think they come off as a little complicated because when you think about it you're like what is a state machine? Like what does that mean to be a state machine?

Speaker 2:

The way to think about it is anything that can exist in a specific state and then transitions between states. Right, that's most web apps, that's most apps that we are building in this context, have that sort of system you can think about, like ticket tracking, e-commerce, order flow, subscriptions, management. All of them have this sort of feel. I think it's important to sort of recognize that. But I've also worked in apps that obviously should have been state machines but were just like a bunch of guard clauses on every method that checks the state and that feels very cumbersome. But if you don't have a good state machine gem or some sort of library to make it work or you don't know about state machines, then that's sort of part of the issue. So it sort of leads you to look at the state machine gems that exist and I think there's state machines. State machines. Workflow was one of them. There's like a few.

Speaker 1:

It wasn't there ASM or something like that. Aasm, access state machine yeah.

Speaker 3:

Access state machine yeah, we use workflow at Podia like heavily so very familiar.

Speaker 2:

Yeah, and I've used access state machine and I've used the state machines gem, I think, or the two that I've used. But most of them work in sort of a similar way, which is they define a bunch of methods that take blocks that then let you set specific states and then set transitions for which transitions are valid, with a block that determines what happens on that state transition. So that's sort of like the idea. This can actually be fine for most apps.

Speaker 2:

The problem is that if you have an app that has like a dozen states or something, these state machines can get very large and if they're all in the same model, then that model can be thousands of lines of code and then that becomes like a nightmare to keep track of and it also means that when editing that class you sort of have to think about like sort of one of the benefits of state machines is that when you're working in them you only have to think about the states that you were looking for, the transition from right, like that's kind of one of the benefits of them.

Speaker 2:

But if all this code is like in the same class and it's all kind of mixed together, then you still have to sort of hold the whole thing in your head, which is not great, so yeah, so this is like a thing that I'm very interested in like playing around with and experimenting with kind of on my own and trying to see if I can brainstorm some better approaches or better ways at like modeling state machines and inter rails in an active record backed app. So I'd love to pick your brains on what your experience has been.

Speaker 1:

For one. It's sort of like you know when you're reading that code if you've never edited before and you see all the guard clauses, like you're saying, like you have to reverse engineer the state machine that's not strictly defined anywhere, which can be incredibly hard to wrap your head around, and you may never wrap your head around it and chances are you will end up with transitions that don't end up in the right state or whatever. That stuff can easily happen when you don't have it like defined anywhere. So, yeah, I think before the episode you said something like if you've got a model that has state or status as a column on it, you should be using a state machine.

Speaker 2:

I thought that was really good. You know it's a little bit of a snarky kind of comment, but yeah, I that's one thing that I believe. I think if you see state in your database column, that is a clear sign state or status. It's a clear sign that what you have is a state machine that's just being hidden. If you're not currently using a state machine, jam or some some sort of state machine for it, that's a very, very clear sign and I think, like it would make your code more maintainable, easier to understand, easier to reason about. It has so many benefits to modeling it that way. That's the number one way to know that it's a state machine. I'm sure that there are other ways that you could pull out hidden state machines, but usually when I see state on a model and I don't see state machine, I like know I'm in for a hard debugging time.

Speaker 1:

Yeah, or anytime an enum is used, that's a good sign that, like you know that you're storing states, but having a clear definition of the state has these transitions to these others, Because the enums are literally like here's zero, it's this name. It's one is this name, two is this name and there's no context around it, which is where the value of the state machines really comes into play. The states themselves are only a sort of a required necessity, but it's really the transitions or the key piece. These are the options you have from here and that's what you need to care about.

Speaker 2:

It also makes them easier to test too, because you know what the discrete states are.

Speaker 3:

If you're like most devs, too much of your time gets sucked up with downtime issues, troubleshooting and error tracking. How can you spend more time shipping code and less time putting out fires? Honey Badger is how it's a suite of monitoring tools especially for devs. It's the only system that combines error monitoring, uptime tracking, cron and heartbeat monitoring into a single clean, fast interface. Sure, you could get familiar with any interface, but why waste your time learning some Franken system interface that looks like an airline cockpit when what you need is clarity and speed?

Speaker 3:

You won't know if Honey Badger will really save you time and trouble until you see how it works in your own tool chain. With two lines of code and five minutes you can see for yourself. Honey Badger automatically hooks into popular web frameworks, job systems, authentication libraries and front-end JavaScript, even fixing errors before your users could even report them. Five minutes of your time with a free trial is all it will take to see if it works for you. It just might be the best five minutes you've spent in a while. Check it out at honeybadgerio. Another thing I find myself implicitly a lot is timestamps A state like oh yeah, like a publish dad or something.

Speaker 3:

Yeah, I find myself relying on. Well, if this timestamp is present, that means it's in this state and that's often assigned to me, like, oh well, I can still track those timestamps and have a state like a state machine that pushes the timestamps. It's just part of its own workflow. That's a very good point.

Speaker 1:

Yeah, Even something as simple as yeah, you've got a draft post that needs to be published, but a side effect of publishing is we need to send out notifications or do something like that. It's not even state itself, it's like a callback of this transition. This move from these two states needs to do some additional work, not just update the column or whatever. Probably anytime you find those methods that are like hey, we're going from A to B and this stuff happens along the way. There you go. Could be the tiniest state machine, Could be two different states, but still important.

Speaker 2:

Those transitions are like the value of a state machine is codifying the behavior that happens on the transition. That is the value in it. That's like all the power that you get out of it and being able to reason about that in a pragmatic way. It's such a game changer for development, I think.

Speaker 1:

Yeah, because the nuances creep up really fast. Where you have using that simple example of going a blog post goes from draft to published, as that step happens, we send notifications. But that's not reality. Reality is you'll publish the blog post and then someone's like, oh shoot, we published it a week early, we need to go back to draft, or something like that. Then we're like next time maybe we don't want to send notifications. There's actually an extra transition in there that skips notifications or something, and you have to keep that in mind. If you don't use a state machine, you can easily miss those extra transitions. Or maybe it's another state is missing. You discover Maybe the notification step is. This happens then immediately, once that's done, triggers the published state or something. We just skipped that intermediate state and we probably should introduce a formal thing for it. I feel like that's another thing. People often don't model well enough, or something.

Speaker 2:

One of the things that I think is interesting in what you were saying there is you're not using a state machine and you're trying to model all this stuff. Now you've got all these hidden edge cases that you probably don't know about. If you try to model a state machine on top of it, you have to deal with those edge cases, because in the draft publish one, it's maybe not that big of a deal to just break those edge cases and not care If it's something like subscriptions management, where you've got customers who are depending on some behavior that you didn't know you would codified. Now to model the state machine, you've got to figure out how to do that. That can be very challenging if you didn't start with a state machine to begin with or very early on, decide that it should have been a state machine.

Speaker 1:

Do you have any advice on how to break an existing system down into a state machine? If somebody is like you know what. You got a really good point. I didn't use one, but I should be.

Speaker 2:

This is a difficult one. It's very difficult to piecemeal it right. You have to eat the whole frog at once. Basically, my advice would be to look at some of the current Ruby state machines. Depending on what you're doing, depending on how many states you have, they may be cumbersome or might be daunting, but I would look at some of the state machine gems. I know we mentioned workflow and ASM, or ASM.

Speaker 1:

There you go.

Speaker 2:

I would look at those, also think this is a use case for single table inheritance too. I think single table inheritance can solve some of these problems. That's actually one of the things that I sort of want to do some more exploration on, because there's a part of me that likes the idea of having a draft postpublish, that transitions it to published post or whatever that sets the state appropriately. There's a part of me that likes the idea of that, but without seeing it in something real. I don't know if that would be good or bad. Actually, I don't know if it would become too un-maintainable to have too many different objects.

Speaker 3:

Yeah, it's an interesting idea, because earlier, when you were saying you see people handling state as a bunch of guard clauses, I was actually thinking, oh, typically when I'm trying to avoid a bunch of conditional logic based on that, it's usually with STI, because I just like subclass and then each thing is its own individual representation.

Speaker 1:

Yeah, yeah, that's maybe one of those where it depends on the complexity of your state machine. Maybe the simpler ones get the simpler solution but the fancier ones get single table inheritance or something like that. A little bit before we started recording the episode, we were talking about even the notification example. Notifications can be complicated on their own, and making a notifier class that's like this defines how all the deliveries happen for the blog post. It could be SMS or browser notifications, push notifications or emails or whatever. And codifying this state machine as an actual concept in your application, not just some methods on your model, but maybe even having a thing that's like transition from here to here. It can verify that you're actually in one of the pre-states that's required to do this type of transition.

Speaker 1:

I feel like there's a lot of times where, as Rails developers, it's got to be a model or a controller or whatever. Have a good one. People don't take enough time to remember that like this is just Ruby and you can write any classes you want, and if a state machine is a critical piece of knowledge you need to understand in the app, make a class or a module that expresses all of that and it could be just that and it can know that we need to operate on a subscription and charges and customers or whatever else. It is the tendency for these have been like it's tied to a model. The model has the state column and that's what we operate on which is limiting, I think.

Speaker 2:

I definitely agree with that.

Speaker 2:

I think for a while, I think, Rails community has kind of gone through phases of what is the generally accepted practice.

Speaker 2:

So we went from like fat controller and skinny model to skinny controller and fat model and then everybody was putting all their logic and service classes and now I guess I don't know what the soup de jure is at the moment. But if you've got a complicated transition of state between like that involves multiple models and like that is a core piece of your business functionality, yeah, maybe encapsulate that into a service class. That's like you've been instantiating call from a state machine transition and treat it that way. I think all of these things are tools that help you reason about the code right. They're supposed to communicate intent to you, and so the reason that I like a state machine is because it helps communicate to me what's happening inside the app. Like that's the thing you want to optimize for right, the computer can do all of this stuff really quickly, no matter which way you write it right. Like it's about who's going to look at it in the future and understand it and be able to modify it or edit it and maintain it.

Speaker 1:

Yeah, because state machine kind of does is rather than I've got a subscription or something and it has all of these methods available all of the time, but there are guard clauses inside of them. You could make it not respond to cancel if the subscription is still pending. Cancel could just only be a thing at that time and then you can inspect the objects and be like, well, there is no cancel method on the subscription and it's like, yeah, because the subscription is not active so you couldn't cancel it or it's already canceled. So why would we even give you the ability to try to cancel a canceled subscription? And you guys ever seen the Gilded Rose Cata? I think James, what's his name? James Edward Gray.

Speaker 1:

The second, I always remember Jagd 2 as his username. His solution for that was basically including modules on instances of the class, and so it was like each one of them could define things that they were capable of. They're all cheeses or whatever it's operating on, and normally every cheese would have every method and maybe some of them would return true or false or have a guard at the beginning. But the way he had implemented it was like this one we create the cheese and then we include these features on just this one piece of cheese, not like the whole thing in general, and I was like whoa, that's mind blowing and I don't think we normally have even realized like Ruby is capable of that. We always write instance methods as sort of like the way we do it, but you can make those as modules you include when the class is instantiated. You check the state and then you include these modules to add features like cancel only if the state was active or something. And I was like mind blown.

Speaker 2:

That is very interesting. I might have to look at that.

Speaker 1:

I'll put that in the notes too, because think about that on the regular, because I didn't even realize you could be that fluid and flexible in Ruby.

Speaker 2:

Did you ever see? He had two talks that one was 10 things you didn't know Rails could do, and then one was like 10 things you didn't know Ruby could do, but one ended up being like 42 things and the other one ended up being like 100 things. Those are my two favorite talks of his. They're so good.

Speaker 1:

They're fast too Like he covers so much ground so quickly and you're just like I feel like I've seen those, but so long ago that I really, really need to rewatch them.

Speaker 2:

So yeah, that sounds right up my own.

Speaker 1:

You got to find the source code for this. But isn't it weird that we can use Ruby every day for 10 plus years and you're still like I didn't know we could do this or think about problems in this way and even just like, yeah, what if this method is only defined on objects in a certain state? Makes a lot of sense, you know especially for like what transitions are available.

Speaker 1:

And it's kind of the duck typing this, of Ruby in general, where it's like, well, if you give us an object, we can make sure that if it looks like a duck and has a quack method, then like we don't care what it is or anything, and it kind of fits that same philosophy. So it's wild to be like there's so many different ways. We've never even imagined how to solve these problems yet. It feels like we should know these things by now, but we're still like discovering new things constantly.

Speaker 2:

And we're still getting new things, like there's still so much to discover in what we already have, but we're still getting new language features and new cool stuff every year and it's I think the best decision of my career was learning Ruby. Like it's such a good language for me, at least for my brain, for how it works and the community is so good. Like you said, there's so much to learn and so much like it's nice to find new ways to get to use Ruby right.

Speaker 1:

Because I guess with other languages you're kind of a lot stricter on what syntax is available and stuff, but with Ruby it's like so flexible to a point where it can become debilitating, almost where you're like I don't know how. I want to solve this problem because I took a few stabs at it and I know that I can do better and I don't want to ship this like version that I've currently got. Even though it's functional, it's not as pretty as I can imagine it could be. A fun little example is this past week. One evening I was like I had this idea that in your active record models you have your associations and you can pass parameters to that and customize whatever on your associations. In the notice gem that I've been working on, we have like deliver this notification by email and then you've got to tell it what email class you want to use the user mailer Okay, do you want to send what method? Do we call on it the new comment method and then we need to pass an arguments or parameters and it's defining sort of all this on one long line of options. One of the things was like to make stuff dynamic. You can give it a symbol as a value and we'll call the method with that same name if it exists, and that's fine.

Speaker 1:

But if you have a bunch of those notifications, you end up with a bunch of methods that are defined on the class that everybody can access and it just kind of isn't organized very well. And I was like you know it'd be interesting as if we could just give it a block and you could just say do config and then config, define like mailer and method name and arguments or whatever, and it was literally two lines of code to add that feature. So now you can, instead of doing a whole bunch of options in a hash, you can just do a config block. And the only thing I had to change was like we check if a block was given to the method and then we yield a hash to it and you can add keys to the hash and voila, you're done.

Speaker 1:

And I was like no way, there's no way. This is that simple and I can change the entire ergonomics of how you like organize these configuration things with two lines of code like mind blowing. And I've been amazed because of like Ruby's ability to do that with the SLs. I guess to the thing that you don't realize is the optional parentheses or the methods that can end with an exclamation or a question mark, add so much to the language. They're tiny but they add a ridiculous amount because the things read so much better that way.

Speaker 2:

Yeah, it's all of these little tiny touches in the language that they all add up. I remember when it was probably from Ruby 1 to Ruby 2, when we got the stabby Lambda syntax for blocks or prox or whatever. Then we also got the hash syntax where instead of doing the equal arrow, you got to-.

Speaker 1:

Yeah, the fat arrow thing. Yeah, instead of doing that.

Speaker 2:

you could do just the symbol colon and it would interpolate the right thing as being a symbol. That was like I remember when that happened and it caused a little bit of it's a bit of a kerfuffle, because if you want that to be a string or something other than a symbol, you still have to use the old syntax. But it's so nice. It's just this little tiny nicety that, just like it, improves your day and it's like Marie Kondo right, it sparks joy every time I think of it.

Speaker 1:

Yes, Every time I answer this. I very fondly remember that. And then it also hated it because if you write a gem then you have to use the old syntax because you're probably going to support people still on 1.9 because it's brand new and it's like I just want to use the new nice features because I know how clean this code can read, but I can't use it, which is like drives me nuts. Yeah, I remember the community was kind of like this is awesome, but we hate it because we can't use it yet. We have enough people haven't converted over yet and it was like yeah, that's an interesting problem. What I wonder is why don't other languages like JavaScript could adopt optional parentheses or exclamations or question marks at the end of method names and no other languages like even bother to try that. It seems strange that they don't care.

Speaker 2:

It's a good question. I don't know. I mean, maybe the people, the developers developing in those languages don't consider those things to be like necessary.

Speaker 1:

Maybe because they've never experienced it, or something like, maybe because they've never experienced it, they've yeah, I've always wondered that because I'm like these tiny little parser changes could make you know for some very much more elegant JavaScript code. Instead of having every method is active and you could just say active question mark to me worth changing JavaScript to support that.

Speaker 2:

It's funny because when I look at JavaScript code and I see something that's like is active, there's a part of my brain that like glitches for a second.

Speaker 1:

Oh, yeah, me too. Every time it's funny because it's like you could just make a small tweak to the language and all that could go away. But I don't know. I imagine for Java. Yeah, just a small tweak.

Speaker 2:

I imagine for JavaScript though it's probably got to be much more difficult because, like you, got to deal with all the browser compatibility. Yeah Right.

Speaker 1:

I mean.

Speaker 2:

I guess now it's different, because you could just like transpile to Right.

Speaker 1:

It's one of those where it's like to get built into the browser for adoption Going to take a lot of time to ship, all that but it's also like not a breaking change that they could totally add as a new feature or something. But I guess they kind of did the question mark dot, like the safe navigation stuff, which maybe they just picked the wrong character for that one, I don't know, reminds me a little bit of one of the things that I'm like waiting for is for Chrome to support grid level 2.

Speaker 2:

I forgot what is the details on that.

Speaker 1:

I forget. I remember reading about it, okay.

Speaker 2:

So CSS grid is like just like the standard grid. Grid level 2 is like sub grid, I think is what they call it. But it's like you place a grid inside of another grid and you tell it to accept the grid stops for the parent grid. So it means that you can take the inner grid and have it conform to the spacing of the outer grid.

Speaker 1:

That's interesting.

Speaker 2:

It is useful for like a. It's useful for a bunch of different types of things. The problem is is that the only browser that supports it currently is Firefox. Oh, no wait, actually I think I think Safari supports it as of the latest Safari release.

Speaker 1:

Oh, wow, safari is usually a little, a little behind on some of those things. Yeah.

Speaker 2:

But Chrome is like I have no idea what it's going to ship in Chrome, Like it's been years and years and years. From what I understand, it's like waiting a refactor of the rendering engine or something.

Speaker 1:

Oh joy, I'm sure that's easy, but like they're literally building almost an operating system, you know, in these, in these browsers, it's kind of nuts.

Speaker 2:

It is. It's like a whole other.

Speaker 1:

Yeah, I always think back to like there's a talk from some GitHub developers that were, I think, designers, but they're, you know, front end developers working on the diff screen and trying to just display a diff with red and green highlighted code. And they were like basically the talk was them reading the internals of the Chromium engine because they were like, well, if you've got million lines of code in a diff and you're trying to display all that, you can't put like a span around every single character or whatever that you're trying to highlight. And if we do classes, that's very inefficient, ids are faster. But if we use a tag like the itag that nobody is using or we're not using anywhere else, then like that's the most efficient. And they're like we're basically just trying to style smh2ml and then ended up, like in the internals of WebKit or whatever, trying to understand how to efficiently write CSS that would render like a giant page and I was like that sounds like quite the rabbit hole to go down.

Speaker 2:

Yeah, that's got to be incredibly challenging, like when you get to the point where the thing you want to render you have to like go and look at how browsers at the source code for browsers and how they are doing.

Speaker 1:

It's like if you're doing something in Ruby and it's tech faults and you end up in Ruby's C source code trying to debug what you're doing, you're so far in the weeds that most people probably would stop and just like all right, let's change what we're doing instead. Yeah, do you have any more hot takes on state machines to draw?

Speaker 2:

No, just that people should use them. I mean I think they are vastly underutilized. That's what I will say.

Speaker 1:

I definitely agree with that. Even just if you are trying to wrap your head around how something works Stripe subscriptions show their flow of statuses and states and stuff Just draw out what you're trying to do on paper in state machine or like a flow diagram format that you will really understand the problem way better than trying to read the sloppy code that tries to replicate that without really defining the state machine. It can be a pretty good eye-opener because then you might realize, like I got a bunch of guards Don't make any sense, because we're trying to protect from using the wrong state to call this thing. It's like we just flip that and do ensure that it's in these states before we do this stuff. Then you might realize there's a bunch of code you could reorganize, throw away whatever. It seems like a very good thing that you know. I don't remember if in computer science we, like I know we did algorithms and stuff, but I don't know if we spend a ton of time on state machines or not in school.

Speaker 2:

I don't remember spending a lot of time on state machines in school. So the place where I really learned about state machines was doing the consumer electronics, like embedded programming, because, like everything you're doing in, there is a state and the state transition happens based on like a button press or a sensor input or something. But it's just sort of funny because I feel like no matter what industry you go into or where you go, like programming is kind of the same. It's the same tools, the same ideas, the same concepts applied to different constraints. So I don't remember learning about them in school, but I feel like most of what I've known now I learned after graduating and I learned by actually doing so.

Speaker 1:

Yeah, we had a couple electrical engineering classes that were required in our CS degree and I remember like we designed a CPU, like a tiny little CPU, from scratch, kind of thing, and it was like it was actually really fun because, similar to the state machine, you're kind of working in that mindset. Then also the cool thing was like, okay, you're sending these eight bits of binary into these eight slots, and then they showed us the like jump from there to assembly, which is like it's just a little word that represents these bits, and I was like, oh, that's cool. And then they showed us to like going from assembly to C, and it was like, oh, c is just like a little abstraction over the assembly. Like I can convert the C call into the exact same binary or whatever.

Speaker 1:

I don't remember most what we did back then, but it was like what? It's just little abstractions over layer, over layer. And then at some point you don't have to think about any of it, even memory allocation, because you write Ruby. So like, wonderful. But going back down the stack, a bit like grab one of those kids electronics projects and like do some of that, because you'll probably end up learning state machines or whatever in those projects.

Speaker 2:

Who knows? I think there was something you said that is maybe a good starting point. If you have a thing where you've got a state column and you've just got a bunch of guard clauses, I like what you said about just draw it out, that is a very good first step. That will give you a clear sign of where maybe some pitfalls are and it'll actually help you. If you choose one of these state machine gems or if you choose to go the STI route or something. It'll probably help you to make sure that you got everything sorted out so you can make that transition a lot easier.

Speaker 1:

Yeah, I'm remembering that maybe in our algorithms and data structures class we had to model a like a vending machine, and it was basically like you selected a one and it's a dollar. So the state machine is we start with the state of zero and they put in a nickel and we go to five, and then we go to whatever and then eventually the transition opens up. That's like you put in a dollar or more so we can go actually execute the thing, but until then you're stuck in a loop of waiting for more money to be inserted because we cannot give you the thing. But we also have the eject button to like refund you all the money and go back to zero. But then it's like you open up that state transition to like okay, now we can give you the item that you purchased, but it goes into another thing which is like if we subtract the dollar from the amount in the machine, maybe you put in the $20 bill, so we need to dispense however many quarters or something in afterwards.

Speaker 1:

And it's like it was just a tiny little example that kind of got you to think about like this is a state machine, a simple one, but one that you interact with all the time and you can really understand it completely and it's trivial but yet shows you quite a few of those things, because somebody could put in a hundred pennies or a $1 coin or $5 and you get kind of all those different options to see like there's loops if they put in less and then just keep in this loop until this thing is available and so on. So I think that's kind of a very common first introduction to state machines. But you can probably Google that and find a good tutorial on that or something.

Speaker 2:

Yeah, I had a friend who asked me a little bit ago about state machines and I want I think that that's a great example, because what you're talking about is you're sitting there waiting in a loop, and the question that I got was like what is the difference between like something happening within the system and something happening from a user?

Speaker 1:

Yeah.

Speaker 2:

I was like, well, there is no difference, right. Like the difference is like something happens, it triggers a thing that transitions the state. That thing could be the user presses a button or we get another coin or whatever. But like that example, because it's sort of it treats it like you're still sitting in a loop just waiting for the user to give you another quarter, and that's the same as sitting in a loop waiting for API call to come back or something.

Speaker 1:

Yeah, and that's how video games work. They're just like an infinite loop and they're like draw whatever screen and we just keep updating it. But it is funny to think about that because it's like, yeah, the web server is just waiting for a request, but we never even like, as Rails developers, like we never, ever touch that. We're just like here's a request and we just handle the event happened and we go do that and we like are just one leg of that loop or whatever, which is interesting.

Speaker 2:

I've never thought about it that way, but that is kind of how it is, Like that's yeah, that's like breaks the problem down where you're not.

Speaker 1:

You're no longer responsible for the loop. You're just doing the job of input and output and we just take whatever you gave us and give you whatever you expect back, and it's not our responsibility for the outer loop. That's Nate Birkopeck's job on Puma. Yeah, okay.

Speaker 3:

We're running up against time here, but before we wrap up, first, really glad that you came on today and hung out with us. Where can people find you online?

Speaker 2:

So I'm off most social media, but I do have a website. So you can find me at Elise Schaefer dot com. You can obviously find me on the Ruby on Rails podcast, and that is at the Ruby on Rails podcastcom. I mean, in terms of social media, the only one that I really still have is LinkedIn. I also have Strava, cycling and stuff, so if you're a cyclist, you can find my Strava. My Strava is linked on my website, but I'll include it for the show notes too.

Speaker 3:

Awesome.

Speaker 1:

Cool, all right. Well, this has been a lot of fun. We will have more conversations in person at RubyConf, so I'm looking forward to that. We will talk soon.

Speaker 2:

Yeah, thank you so much for having me. This has been an amazing conversation, so I appreciate it and I look forward to chatting in person in a couple of weeks.

Ruby on Rails Podcast Host Transition
Ruby
State Machines in Code Development
Language Features and Web Development Challenges
State Machines in Programming