I’ve been going back and forth about what to put in this newsletter about Modern Front-End Development For Rails. On the one hand, it’s a big deal for me, and it’d be great for me if people bought it. On the other hand, you’ve likely heard me talking about it for a year and you’ve probably made up your mind. (If you haven’t, would you consider buying a book?)
I did realize I had a weird, niche topic about the book that I wanted to talk about.
Writing example code for a workshop or for a book-length tutorial is an unusual set of constraints on code. Here’s how I think about writing example code, and how the examples in MFEDR evolved, and also how I changed the example slightly between the book version and the workshop version.
The key thing to remember about a code example is that, almost by definition, the people who are going to be setting it up and walking through it don’t already know the tool or technique the sample is there to illustrate. Issues that you, the example creator, might take for granted in setup or understanding the code are not necessarily going to be as easy for the consumers of the example.
You want to reduce the amount of friction and complexity in dealing with the example.
It needs to be easy to set up. This is especially important in a workshop situation, but it’s also true in a book situation. In small-group workshops, I’ve lost hours waiting for the last person to get set up, in large-group workshops, I’ve had people have to bail because they couldn’t get set up. In book situations, people get very mad if setup that is supposed to be easy turns out to be difficult, and will sometimes just drop the book entirely. I don’t like having my books make people mad.
Preparation and communication go a long way here. In a workshop situation, give people a way to get set up before the workshop starts and announce that as often as you can. Your setup should list all the dependencies and their version numbers. It’s guaranteed that you’ll discover that you forgot that something is a dependency because you are used to just assuming that it’s there on your machine, so have somebody try it out first. (For example somebody installing a new version of Ruby might not have bundler installed…)
You want to minimize dependencies. My setup for in-person workshops got a lot easier when I switched from MySQL/Postgres to Sqlite3 and delivered the seeded database in the code repo. This not only skips the db setup, migration, and seed steps, but there’s often one person who needs to install the database and that’s a huge hurdle to do right at the beginning of a workshop. (Sqlite3 is easier to install)
On the other hand, sometimes there’s nothing you can do. I was once giving a Ruby workshop and a person walked in five minutes before the start of the workshop with a Surface tablet (not laptop), and wanted help getting set up. He was, sadly, disappointed.
Make it easy for people to contact you if they have a setup problem.
Do the setup yourself, if possible on a different machine than the one you normally use. Have somebody else you know try and do the setup in advance.
It needs to focus on the tool or technique you are trying to teach
This can mean a couple of different things.
One is that a good sample app is pretty thin. It doesn’t need great admin forms, or perfect security (unless you are teaching security). I don’t deliberately add bugs or code I think is bad – you never know who is going to copy what – but the parts of the application that are not directly at issue are deliberately underbuilt.
Similarly, a sample app is not a time to take a flyer on a non-standard tool that doesn’t directly apply. For the money book, I felt for a second that I was free to do whatever I wanted in my own app, and I did all the view code in Slim. Nothing in particular against Slim, but it was, and is, not a tool with a huge share in Ruby, meaning that most people who read the book needed to learn a completely separate view language in order to learn how to better process credit card transactions. It was not my best choice.
You also want the task you do in the sample to show off the thing you are trying to teach, which is where you get tension between realism and focus.
Over the course of a book-length example, you may find halfway through the book that the structure of the code doesn’t quite match what you want to do next, meaning that you need to either backtrack and change all the prior code, or you need to explain what is basically an logistical change to the reader.
I don’t have a hard-and-fast rule about this, but in general if it’s basically a bug, then I try and go back and fix it, but if it’s an assumption that turns out to be not correct in the future, then sometimes I’ll leave it in so as to have a discussion about the code structure.
For example, the current beta version of MFEDR has one case where I have to back-track because I inadvertently placed a DOM change in the wrong part of the DOM tree – it looks fine on screen, which is why I didn’t notice until I went back to do more changing. That one, I’m going to fix at the point of the initial problem. On the other hand, there are a lot of view partials in the book that use
current_user, which causes problems when we start delivering those partials in the background via ActionCable, the session no longer exists, so
current_user errors. That issue, I’m going to leave in, because the discussion about why it needs to be changed is valuable.
That said, for the workshop, I just did both of them right in the background, I’m not going to have time to walk through all the changes.
An Example Example
The original goal of MFEDR was to show off Stimulus, which meant creating a sample page that was complex enough to allow for client-side logic, but not so complex that people would be wondering why it wasn’t a single page app. I wanted to show off what Stimulus is good at, which to my mind is responding to user events with logic and CSS manipulation.
The original client app that I had worked on that excited me about Stimulus was not an option because it had too much domain-specific logic, and taking that logic away left me with what was pretty much just a form.
I fell back on a scheduling page that I had written and re-written a couple of times. Here’s the “real” version, though I don’t work for them anymore. It’s a schedule of some sorted events with a few filters.
This worked for me. The data model was not complicated, the filters would be relatively generic and easy to explain, and it was somewhat in the neighborhood of real life. Though in the book example I changed it to a music festival, and used the Faker gem to generate band names. (In the first version of the book, the festival was called “North By North South”, which is a reference to the TV Show The Good Place, but nobody got it and people thought it was a mistake, so now it’s just “North By”).
The original plan was to do the same page in Stimulus and then again React, but I quickly realized that would be extremely confusing to the reader if the book went back and forth between the two examples. I came up with a second page that used React, specifically, a page that let you choose tickets in particular seats, with some contrived logic as to what seats were available based on how many you wanted. The idea was to show off React by having a page with more internal state – the set of tickets being bought – and also to allow for some common React issues, like walking through loops and such.
Over the course of the book both examples got more complicated, storing more state and talking to the server. Very late in the first draft, I had the idea to add an appendix to write the React page in Stimulus and vice versa, on the theory that might suggest some issues about each tool that the custom page didn’t.
The release of Hotwire changed the book examples in a few ways.
- The existence of Hotwire meant that there were a different set of features I wanted to show off in the book, especially the kinds of things in this post.
- Some very clear signals from DHH and the Turbo team about the preferred Rails way meant that I wanted to rethink a couple of examples in the book, particularly the ones that were dealing with client-side state.
- The existence of Hey.com gave me an existence proof of a couple of cool tricks you could do with Hotwire and I wanted to work them in if possible. Now I actively wanted to show that you could use Hotwire in a place where others might choose a single page app.
I added a “Favorite” feature to the schedule page, allowing a pretend user to make a particular event a “favorite” and listing the favorite events at the top of the page. Somewhat coincidentally, this made the sample page echo Hey with a small number of important items up top and a longer list below. More importantly, the favorite button gave me a feature that was not wildly implausible, easy to explain, easy to explain why you’d want to implement it client side, and required redrawing a couple of places on the page to work, making it logical to show Turbo Drive, then Turbo Frames, then Turbo Streams then Turbo Streams with ActionCable.
The React page didn’t need to change at all, and it was only at the end when I was re-doing the appendix that I realized how much more functionality I had given the Hotwire page—it took a lot of React code to make it work.
I’m never completely happy with the long-form examples, there’s always something in the fake logic that seems contrived, or requires too much explanation. (The first time I tried to do it in this book, I wound up showing people how to parse recipe text, for some reason). But I thought the MFEDR example turned out pretty well. The user login is a slight distraction, and the ticket logic on the React page is a little forced, but I think it does a decent job of showing off the tools.
Next time: I think we’ll go to a related kind of sample code and talk about take-home interview problems.