The Changelog: Software Development, Open Source - JavaScript sprinkles in Basecamp turned Stimulus (Interview)

Episode Date: March 6, 2018

David Heinemeier Hansson joined the show to share the story of how JavaScript sprinkles in Basecamp evolved into a full-fledged framework called Stimulus. We talked about ins and outs of Basecamp as i...t is today, Ruby, JavaScript and David's somewhat new found love for that language. How they open source because they can. And David's new YouTube series called "On Writing Software Well".

Transcript
Discussion (0)
Starting point is 00:00:00 Bandwidth for ChangeLog is provided by Fastly. Learn more at Fastly.com. Error monitoring is provided by Rollbar. Check them out at Rollbar.com. And we're hosted on Linode servers. Head to Linode.com slash ChangeLog. This episode is brought to you by Rollbar. Rollbar is real-time error monitoring, alerting, and analytics that helps you resolve production errors in minutes.
Starting point is 00:00:23 And I talked with Paul Bigger, the founder of CircleCI, a trusted customer of Rollbar, and he says they don't deploy a service without installing Rollbar first. It's that crucial to them. We operate at serious scale. And literally the first thing we do when we create a new service is we install Rollbar in it. We need to have that visibility. And without that visibility, it would be impossible to run at the scale we do.
Starting point is 00:00:49 And certainly with the number of people that we have. We're a relatively small team operating a major service. And without the visibility that Rollbar gives us into our exceptions, it just wouldn't be possible. All right, to start deploying with confidence, just like Paul and the team in CircleCI, head to rollbar.com slash changelog., head to rollbar.com slash changelog. Once again, rollbar.com slash changelog.
Starting point is 00:01:17 From Changelog Media, you're listening to the Changelog podcast featuring the hackers, leaders, and innovators of open source i'm adam stachowiak editor-in-chief of changelog on today's show jared and i are talking to david hanmeyer hansen sometimes better known as dhh we're talking about how javascript sprinkles and basecamp evolved into a framework called stimulus we talked about the ins and outs of basecamp as it is today. Ruby, JavaScript,
Starting point is 00:01:45 and David's somewhat newfound love for that language, how they open source because they can, and David's new YouTube series called On Writing Software Well. So David, I guess the thing we're here to talk about is how the JavaScript sprinkles that were inside of Basecamp turned into a full-fledged framework stimulus JS. Can you tell us the story of sprinkles to stimulus? Absolutely. we started dabbling with JavaScript, both in the form of sort of pre-AJAX and then post-AJAX, and then through Prototype and jQuery and all the other libraries, we've always adopted a sort of distance approach somewhat. That what we're trying to do is we were trying to build some html documents um that were linked together i know this is terribly novel um but then we would adorn them sort of progressively progressive enhancement
Starting point is 00:02:52 is sort of the fancy term for it but that's right doesn't even fully describe our philosophy because it's not so much just progressive enhancement in terms of oh your entire app should be able to be fully functional if someone turned up javascript that't why we did it. That wasn't why I was interested in progressive enhancement. Progressive enhancement was more a architectural technique of how to build great applications, which is actually similar to how I came to REST and the REST principles for building HTTP applications. It wasn't so much that I had this pure affection for representative state transfer and the theses behind that. It was simply because it was a wonderful architectural pattern for guiding development and guiding
Starting point is 00:03:42 how I should put an application together. And so it is with progressive enhancement that using HTML and having the server side generate that, and then sort of sprinkling little bits of dynamic dust all over the application. Oh, this little button, instead of being a full page change, we're just going to have it dynamically update a tiny bit of the page, which is really appealing to me because the type of applications we built at Basecamp, including Basecamp itself, lend itself very well to that style. And I think that's perhaps where some of the differences sometimes come in, that Basecamp and applications like it,
Starting point is 00:04:23 including GitHub, that uses a very similar style, even if we don't use the same frameworks, they have something called Pjax that was predecessor to Turbolinks. And that idea, which we can talk about later too, they actually go well together, Turbolinks and Stimulus. So that's part of a two-pack punch. But in any case, that applications like that, where it's not about presenting a, let's say, a desktop like super high fidelity, super connected UI, where you're sort of changing a little thing over here. And then there's five different other points that need to update at the same time. That was the world we were in, right? And some people are in a different world, right? Like if you're trying to make some sort of dashboard interface where you're tweaking little dials
Starting point is 00:05:09 and having all sorts of ramifications and updates you have a different domain and you should actually use different solutions for it that's one of the things that long has annoyed me both with software development in general but but JavaScript development in particular, was this idea that there's one template for applications for the web, and that we should all embrace React and Redux as life and savior here, or before that it was Angular, or before that it was something else, right? That we have all the same kinds of applications applications and they all fit in the same mold. And I just couldn't relate to that at all. So that's why for however long it's been that we've had these sort of heavy JavaScript frameworks that used clients at MVC and tried to do all the generation of HTML on the client side, we've rejected that.
Starting point is 00:06:05 We didn't see the fit. First of all, it didn't fit, obviously, with progressive enhancement, but it also didn't fit with what we were trying to do or made anything better. Over the years, we've had our dabbles in using frameworks like that, and it never ended up that the code was better afterwards. One of the techniques that I'm very fond of is doing the ab you take a piece of real production code a real feature and you write it five different ways and that just tells the truth incredibly quickly and the truth that i
Starting point is 00:06:37 derived from that sorry go ahead i was gonna say so in the process of, did you try out some of the, like an Angular or React and dabble with the Basecamp source code and do these different things? Yep. I tried a bunch of different frameworks. Actually, just before going head into stimulus, I did another broad search, essentially evaluating all the frameworks that were already out there and seeing do you know what i'm i don't necessarily want to create another framework we have frameworks coming out the wazoo at base camp right like i have my hands plenty busy with just rails and turbolinks and whatever is there a way that we can simply just adopt one of the existing frameworks as we actually did um with jquery right so So when jQuery was the hot sh-
Starting point is 00:07:25 We just decided, okay, we have this other framework prototype that we had extracted from Basecamp. But it wasn't really different enough from jQuery. And jQuery clearly had the momentum. Let's just switch to jQuery. And we did the same thing with Rails, right? For many years, Rails shipped with jQuery in the box because it was just, that had the momentum.
Starting point is 00:07:47 It was close enough, and it was actually a great framework. I, to this day, still like a lot of things about jQuery, and I think its focus on ergonomics and API design were wonderful and in some ways lost in this transition to the so-called modern era of JavaScript development. In any case – where was my train of thought here? Did I try these things? Was that where we were coming from? Right, yeah, exactly. I kind of went down these rabbit holes. Because you're such a, you know,
Starting point is 00:08:15 you're the kind of person who has your own thoughts, has your own viewpoints on elegance, especially when it comes to code. And it would make sense that maybe you wouldn't try it, but it seems you did. No, absolutely, because I get inspired by it too, right? Oh, that was where we were coming from. Whether there was another existing framework out there that could serve our needs.
Starting point is 00:08:34 And I mean, I'm sure there would be. I mean, it's not like the most terrible thing in the world would be if we used React for some things, for example, right? I don't have any fundamental opposition against that in fact i think react in particular had uh an incredibly correct core insight that instead of maintaining this complicated sense of state you would just blow away the world and re-render it every time i think that's a great insight and actually quite similar to our views on how to do things. It sort of didn't went downhill from there, in my opinion. That was the sparkling moment of where I thought like, oh, there's something really interesting there. And then
Starting point is 00:09:14 I started seeing sort of the mishmash of smashing all the considerations and concerns around competence into one big file. Like we've spent, I don't know how long, trying to separate things out such that we can be on different rates of change and all these other good things. And now here we go, React, HTML smashed in with code, smashed in with state management, smashed in with everything. And I thought, I don't think that's actually progress. So in any case, I reviewed all of these things. And then I also reviewed the JavaScript ecosystem at large. And I actually liked a whole lot better what I saw there than what I saw in
Starting point is 00:09:53 the particular framework expressions that came from that world. I love absolutely the fact that ES5 onward was such a better language, especially for the type of JavaScript that I wanted to write, which was a more object-oriented style, obviously influenced by the fact that Ruby is my true love. And I like that style of programming where it's mostly object-oriented, and then you sprinkle in some functional programming techniques where they make sense. But at a core, I like to structure my code in an object-oriented manner. And ES5 forward just made that not be this horrible hoop-jumping exercise to do so, where we had to use CoffeeScript essentially to get an even halfway sane syntax for declaring classes. So I saw all that progress in the JavaScript ecosystem and thought, this is wonderful. And it's extra wonderful that we don't have to wait for the browsers to catch up.
Starting point is 00:10:53 The fact that we have Babel, the fact that we have Webpack, the fact that we have this whole tool chain that allows us to use almost all of the future heading features of JavaScript today in existing browsers that people are actually using, that was what was so exciting. So I basically took that exploration and said, all right, I've examined both the ecosystem at large and the particular frameworks. I don't care so much for the particular frameworks. I care for the ecosystem improvements. What can we do here? Can I just try to get my sense of progressive enhancement, my love of sprinkles into a more cohesive structure that at first it wasn't even about the rest of the world.
Starting point is 00:11:35 It was just about how we write JavaScript at Basecamp. It was about reforming that way. Because what I had come to dislike was we had such a high standard at Basecamp for writing beautiful Ruby code. And then we had a very uneven standard in some ways for writing JavaScript. On the one hand, we had some wonderful deep diving JavaScript explorations with Sam and Javon. They've made both tricks and they've made turbolings and it's beautiful, wonderful code. And it's really pure and wonderful.
Starting point is 00:12:06 And then we had specific support sprinkles for a feature here, a feature there. And we had like four different styles of doing that, four different ways of attaching event handlers and so forth. And someone coming in new to the Basecamp code base would go like, which, which paths should I follow again? And then usually they just open some file that vaguely resembled what they were trying to do and kind of follow that, which wasn't great, right? You probably had heaps of CoffeeScript code at this point too as well, right? Which actually, I mean, CoffeeScript is not one of those things I look back on with any sense of regret. I think CoffeeScript was a monumental step forward for the syntax of JavaScript prior to ES5.
Starting point is 00:12:54 And in some ways still is, but the gap has now narrowed so considerably that I don't know if the CoffeeScript path is necessarily worth it anymore. But it was totally worth it for those years when all we had was ES3, right? How are you guys managing that migration inside of Basecamp? Are you file-by-file converting it to plain ES5 or ES6 JavaScript? Are you leaving the CoffeeScript in place? What's the progress on that?
Starting point is 00:13:22 How are you guys doing it? We're basically looking at things in sort of new horizons. When we make something new, we will make it to the best of our abilities, to the best concepts and whatever that we have, which today is stimulus. So when we write new features, we write stimulus update them in some way we will sort of weigh whether the change is large enough to warrant a full conversion to stimulus or we should just leave it in place because the thing is you don't really need to do this mass migration the wonderful thing about having um babel and these transpilers is the fact that we can mix and match as we please in fact we do even with modern code.
Starting point is 00:14:05 Stimulus itself is written in TypeScript, not in just vanilla ES5 or 6. And that's because Sam and Javon enjoy using TypeScript when they're writing framework code. And I'm not a huge fan of sort of statically typed or explicitly typed, I should say, code. So that's not what I really want to write. And it's not what we need to write when we write features. But they enjoy doing it for the framework itself. And since they're doing the work, I'm like, of course, you guys get to then pick what you want to do. It doesn't matter.
Starting point is 00:14:39 It all just compiles down to the same thing in the end. So what do I care whether the parts of stimulus that I didn't have to write is written in typescript or coffee script or whatever there's something to be said for having a general style in your application code perhaps but i mean these aren't drastically different languages right like they're like dialects like i'm from denmark and in copenhagen we speak dialect, and I mostly still understand people from Jutland and the dialect that they speak, and it's actually not a big deal. I think people have a tendency to make it
Starting point is 00:15:11 a much bigger deal than it really is. That makes a lot of sense. I know as somebody who has dug into the Turbolinks source code, and I've written a fair bit of CoffeeScript back in the day, but hadn't for maybe a year, 18 months. As a casual contributor, a potential contributor, I may have just opened a bug report or something, but looking at the Turbolinks code, which is CoffeeScript,
Starting point is 00:15:34 I know that there was definitely some cognitive overhead, some catch-up I had to do in order to read that dialect. I think on the other hand, TypeScript actually makes, for libraries, actually makes it easier to contribute because of the documentation available and the types being so obvious and stuff like that. Whereas CoffeeScript may have been a detractor for third-party contributors. I think TypeScript might actually make it even easier for people to get involved. Maybe.
Starting point is 00:15:58 I'm not so convinced that that's the main barrier to entry. In fact, I think that technologies have a tendency to overstate the differences in the technology choices versus the actual cognitive barrier there is to understand systems. To contribute to, say, Turbolinks, there's a fair conceptual model that you have to understand before you can contribute. I think climbing that hill is a taller one than the subtle dialect differences between CoffeeScript and either ES5 or 6 or TypeScript. But I mean, to each their own.
Starting point is 00:16:35 And I think what's just great is the fact that we don't have to go through these violent transitions where in order to have new features, for example, of our application written in stimulus that uses TypeScript written in ES 506. We don't have to rewrite everything that we did before that, because I think those types ways, it's actually a blessing that we're using transpilers all over the place. And it all just boils down to whatever you compile it to, whether that's ES3 or 5 or whatever your final output target is, that it just matters less and less these days. I think that's real progress. Since you mentioned Sam and Devon, and from what I understand, the process was, it sounds like, you know, you were doing some evaluation of JavaScript, the ecosystem. You had done some research, and one day you prototyped something, and that kind of worked. And then Sam and Javon took that and rewrote it into what is now Stimulus, and that's what you're talking about, which is TypeScript, is the language that that's written in. Can you kind of walk through that process of discovering this
Starting point is 00:17:48 and kind of getting to the point where you could prototype something and what that was like and then the transfer from you to them and how that played out? Sure. So as I said, I did this huge survey of the landscape of all the major JavaScript framework. And I read through all of them, and I played with all of them. And I tried to see which ideas I could get inspired by.
Starting point is 00:18:12 And then I started up basically just playing with all the new features in ES5 and 6. This was sort of the first time I had really dug back in and tried what's at the forefront of the JavaScript ecosystem development in quite some time. And I started using all the Babel packs for all the in-progress proposals for all sorts of things. And I just wanted to sort of like, if I could use the latest and the greatest, what would that feel like? So I played with a bunch of different things. At first, it was just experiments, general experiments. And then pretty quickly thereafter, it become focused on, OK, let me review all the JavaScript we have in Basecamp. Let me try to see if I can pick out and extract the best styles that we're already using and kind of gel that into a framework that will guide people to stick with that style.
Starting point is 00:19:07 Because a lot of what we had was basically just sort of subtle conventions of writing code, which I'm a big fan of conventions, but I think they're much stronger when those conventions are backed up and enforced by a framework. So that was basically what we're trying to do. I wasn't necessarily trying to invent anything here as I usually do with frameworks. stimulus was going to be, and wrote it in ES6 with a bunch of plugins. And there was enough there, it was sort of stuffed out in some ways, it didn't have the full mutation of server and so forth. But my sense of the design was really focused around like, let me take an existing piece of JavaScript code in Basecamp that supports a given feature that I don't around like, let me take an existing piece of JavaScript code in Basecamp
Starting point is 00:20:05 that supports a given feature that I don't really like, that I feel like is messy or smelly or whatever. And then let me rewrite it in this proposed format that I have for stimulus and see if it's better. And I rewrote a bunch of different pieces of functionality. And I was astounded by just how much nicer they were to work with when I had rewritten them in stimulus. So after going through that process, I sort of chimed up Sam and Javon, who've been doing most of our deep dive science project, the JavaScript development for a long time, including both Turbolinks and Trix. So they were sort of the natural team within Basecamp. We call them research and fidelity to take this on. And I basically just I wanted what I had written up to really work and not just be stopped
Starting point is 00:20:57 out and not just be a prototype, but be the thing we actually wrote new JavaScript in. So they took this on and integrated another framework that Sam had been working on around mutation observers called Sentinella. And we ended up merging the two directions and it became Stimulus. And they, as I said, they rewrote the whole thing from scratch. In fact, since I wrote the initial prototype of the framework, I haven't written a single line. I think if you do a git blame on the
Starting point is 00:21:25 current repo, you're not going to find my signature on any of the lines written in TypeScript. My role sort of just shifted from, okay, I built the prototype and I have a very clear idea of where I want the final API to go, what the client code should look like. So let me provide that guidance and let me help sort through some of the conceptual issues that we then faced on how to design the API, especially around targets and so forth. And here we are. This episode is brought to you by our friends at Linode. Everything we do here at Changelog is hosted on Linode cloud servers. Pick a plan, pick a distro, and pick a location,
Starting point is 00:22:33 and in minutes, deploy your Linode cloud server. Duel-worthy hardware, native SSD cloud storage, 40-gigabit network, Intel E5 processors, simple, easy control panel, VMms for full control running docker containers encrypted disks or vpns 99.9 uptime guaranteed 24 7 customer support 10 data centers three regions anywhere in the world they've got you covered they also have cloud.leno.com which is an open source single page application find that at github.com linode manager plans start with one gig of ram for five bucks a month or high memory plans
Starting point is 00:23:11 at 16 gigs head to leno.com changelog get four months free with their basic server twenty dollars in hosting credit once again leno.com slash changelog. All right, so let's talk about the architecture, the concepts of Stimulus, how you designed it, and how it works, and how you use it. So one of the things I really wanted with Stimulus was I wanted to solve a couple of specific problems or bad patterns that I was seeing in our Sprinkles code at Basecamp. One of the first things I wanted to address was the notion of how do you find the elements that you want to mutate or work with? And we had a bunch of different styles. Sometimes we were using a hierarchical approach where you'd say like, oh, give me the parent of the parent of the parent here. I know that the structure of my DOM tree is like this, and I know I want sort of the third parent up. That's a pretty brittle way of targeting elements,
Starting point is 00:24:25 right? Like someone reorganizes things or puts them in a different way and all of a sudden you're getting the wrong element. So that wasn't a good pattern. Another pattern that we've used was targeting elements by finding them through CSS classes. So we'd say like, give me the elements that match this CSS class, which on the one hand seems okay, because a lot of times the CSS classes are explanatory. They say like, oh, this element is about the title of a person or something. So when you query for that in the code, it kind of explains what you're trying to get. But it's also pretty brittle. And it's also not compatible with a lot of the modern CSS styles of writing classes, which are things like BEM, that have a very particular way of writing the class names, sort of the BEM format. That actually detracts a bit from when you're trying to use them as code identifiers, but they're very helpful on the CSS side, right?
Starting point is 00:25:22 The designers at Basecamp are really happy with BEM and the advantages that BEM affords them. But it's brittle. Well, it's two things. It's ugly, and then it's brittle. Like, it's ugly when you're trying to target elements that have BEM classes in JavaScript code because BEM has this format that makes sense for CSS and doesn't make sense at all for code.
Starting point is 00:25:44 So I didn't like the ugliness of the code, and I also didn't like the brittleness of it. But that BEM oftentimes, like you add another dash, dash, down, or dash, dash, pad, or whatever it is that you add to your BEM class to ever so slightly tweak it. Well, if the designers were doing that, well, again, they broke the code. So that sense of brittleness I wanted to sort of get away from. And that's where the concept of targets came up. Basically, stimulus implores you to only find DOM elements you want to work with through the concept of targets, which is basically just an explicit name that says this element is going to go by this logical name that belongs to this controller. And then we can move that name around and it's not tied to the specific type of the element.
Starting point is 00:26:31 This could be an input element. It could be a button element. It could be a span element. And as long as it has a data dash target that's of a certain thing, you can always find it, which not only gives you this sense of clarity around like what elements when you read the HTML code are actually used by the dynamic behavior. And in the code itself, it's very clear when you're referencing a specific target, what that target is and what the purpose is. It also gives you a sense of generic distance from the specific structure of your DOM tree. As I said, a data target of, let's say, hello.name can be applied to an input text, a text area, a span element. So you can write these generic controllers that work with all sorts of different kinds of specific DOM tree expressions, which is really neat.
Starting point is 00:27:30 Because that was the other thing I noticed when I was reading through the Basecamp code base, that we have a lot of feature-specific JavaScript that really was quite generic in its essence. And it was only tied to a specific feature because it was naming certain types of DOM element types, or it was specifically naming certain types of CSS. So you couldn't really reuse these pieces of feature from one area of the application to another because they were tied to a specific screen and a specific layout. And I wanted to get a bit more generic around that so that React does and what a lot of competent style development does, because it doesn't afford you this sense of reuse, that you can develop generic concerns and generic aspects of your dynamic behavior that you can tie to any DOM tree. So that was one of the considerations.
Starting point is 00:28:45 So that's the target concept. That's a prime motivator. And then the other thing, there's really only two other things. There's controllers and then there's actions. And actions are quite similar to targets. They're the trickers. So a lot of code we had in Basecamp was using sort of explicit event handling, where we would tie an event handler to usually somewhere up the tree to some parent. And then we would sort of interrogate that event as it bubbled up, see if it was relevant for the behavior we were trying to we were using these attributes called data behavior, and then we would scan these data behavior attributes as the events bubbled up.
Starting point is 00:29:31 And then if the attribute was a match, the data behavior was a match, we would trigger the behavior. Well, that does not provide very readable code always, I'd say, that sort of sometimes we would provide a data behavior on a parent element, and then there would be specific DOM elements inside of that parent that would trigger behavior, and we would catch these events, and we would do something. And one of the things I really disliked about that was I wanted to get to the point where if someone opened up a piece of HTML, they could see what was going on, that it didn't have this shadow land of event handlers living somewhere in some JavaScript files far, far away. So you couldn't tell what the HTML actually wanted to do. I wanted it to be explicit such that, hey, if you click this span, you click this button, you know what's going to happen.
Starting point is 00:30:25 So that's the concept of the actions, that we make those explicit in the HTML itself. We don't hide them away as event handlers in the JavaScript code. I mean, underneath there's an event handler, and that's what stimulus provides you. It provides sort of the plumbing to do that. But what I found was a lot of JavaScript code was very, let's say low level. It was very sort of, yes, event handling is the way that we process this way. And we deal with the with the UI, but that doesn't have to be the way we actually write it. And it certainly isn't the way, the best way to provide understanding of how a system works.
Starting point is 00:31:02 So now we have, you can do data dash action on a button or a span or an input or a submit button or anything else that you want when the user clicks that or submits that or hovers on that or something else, some other sort of event trigger, you can trigger a specific action and that's spelled out, right? So it's data dash action equals, for example, click points to hello, add sign greet. So you read what that button does, right? You don't actually need to read the code. You can read, okay, if a user clicks this button, I'm going to call the greet method on the hello controller. That's super explicit.
Starting point is 00:31:41 And it means that most of the time, I don't even need to look up what the code actually does. I don't need to look up the underlying JavaScript controller to understand what actions are available on this view. And I found that that was just so liberating. The second part of that was that just like data targets, the actions were generic and they could be moved around. So if we currently have an action on, let's say, a button and we move that action to a link, the controller could remain unchanged because the controller didn't actually care or know what type of element invoked its functions. quite different from when you marry the HTML structure with your component and with your dynamic behavior, then you're kind of, you're locked in step and you can't reuse these things and you can't move them around. So that seemed like a big advantage. And then finally, the last concern or the last concept is this notion of the controller, which is basically an encapsulation of
Starting point is 00:32:42 all the behavior that relates to one aspect of one feature of the system. And that's where we basically just use JavaScript classes. And these classes have methods on them. And these are the methods that we call through the action triggers. And those actions and the methods that they correspond to interact with the targets that we've named. And that's it. There's three basic concepts.
Starting point is 00:33:09 And it doesn't take a long time to learn it. Even without learning it, you can read the code, you can read the HTML structure, and you can understand what's going on. And that's really all we needed. In fact, I was kind of shocked when I first started extracting this stuff. I was kind of thinking, oh, man, there's going to be so, so much stuff here. And it was the real epiphany of seeing that those three basic concepts, the controllers, the targets, and the actions were enough to extract such a wide body of behavior from Basecamp. Going back to the targets for a second, I guess I have a comment and then a question as well. So I between like selectors class names you know dealing with the design side dealing with the functionality side and so like what what i've been doing for a long time is just using like a js dash prefix
Starting point is 00:34:16 on a class name and saying js dash and then you're basically doing a target and that is then a signal to the designer that okay this this class does not have to do with the look and feel this is a js specific thing it so therefore they won't get changed based on someone trying to change you know the way something looks and then secondly it also signals that this thing has some javascript attached to it somewhere because like you said we've we've detached the handling to you know someplace in the sky um and so there's a little bit of a signal there but um i like the data dash um way that going about it there's no drawbacks and the i guess the question comes in when it comes time
Starting point is 00:34:59 to actually modify things you mentioned bem and the problem is you know you get class names pulled out from underneath you or what have you. These are issues. And this is genericizing that and pointing it out of the class name, putting it onto a data attribute. But how can you genericize it when it comes time to actually modify the elements? For instance, this click handler actually hides an element or changes it to a variant that's a larger version or a smaller version, aren't you still dealing with class names in terms of the current look and feel of elements? Or is there somehow that you guys are also genericizing that
Starting point is 00:35:35 so you don't have to worry about the BEM class names in your controllers? I love this question because this is literally sort of the fourth concept that we'll be introducing shortly and that I've been working on for some time. It's exactly as you say. We do almost all of the mutation of existing elements through classes, whether we want to hide something. Well, that's having a class that hides it or we to show something, or we want to play an animation, we use CSS animations. Classes are really the way to mutate the DOM the vast majority of the time. And those classes are explicit, right? Like they're BEMed or whatever they are.
Starting point is 00:36:17 And you shouldn't let those BEMed class names leak into your code because you don't want your designers to have to open up some JavaScript controller just to Change a BEM class to add a bit more padding, right? so what we're going to basically do is is a similar construct where you can
Starting point is 00:36:38 declare a data attribute that includes the BEM class in the HTML Which is the is where the designer would be changing it around. And then you can reference that BIM class in your code and say, hey, I want the CSS class that's for hiding. Give me that class. And then apply it to this element such that we return it to this sense of genericism. And we're going to be working on that next. I'm hoping that stimulus 1.1 will include the abstraction of classes into this structure. So we can use logical class names that make sense for the code rather than concrete class names that make sense for the designer, that adhere to BEM, that do all these things. Does that mean that the class name will get set through a data attribute? Exactly, yes.
Starting point is 00:37:28 So there will be somewhere on the, for example, on the controller, so they can be changed by the designer in the HTML. So the designer does not need to monkey around with the controller, at least as long as there's a stable sort of set of logical class names. If they add additional class names or whatever, you might still have to have some involvement. But many cases especially with bem right bem has this idea
Starting point is 00:37:50 that you can mutate and you can combine a single presentation of an element through mutation of one class name right and that is is really something we want to abstract and get away from like there should not be bem class names inside of a controller they should be logically referred to it would be rad if there was some sort of declarative way that you could set that all up up front maybe in one place where you could map these things you know whether it's just a map in your javascript code or something where it's like these logical representations, because there's a handful of them. Like you said, you could cover 80% with defaults.
Starting point is 00:38:31 And these map to these particular class names, just so that the designer is not necessarily having to add data dash, BEM or class name to all of the elements all throughout the HTML. Well, you only have to do it for the CSS classes that you need to dynamically apply. Remember that. Most of the CSS classes you don't need to do this work with. It's only for the ones you need to dynamically apply to something like if you have a specific class for hiding an element or something else like that. So I don't actually think that in most cases you can go generic with them,
Starting point is 00:39:05 especially if you follow BEM, that a specific presentation of one feature might have a logical class name for hiding things, but the concrete implementation in BEM for hiding something might be slightly different than it is somewhere else because it adds or removes padding or margin in some ways.
Starting point is 00:39:25 So we're still sort of feeling that out for now. I'm pretty confident that a huge step forward would simply be to go abstract with the CSS classes you need to dynamically apply and then declare them either in the same element that holds the controller name or on the target or somewhere else where it makes sense. Just disconnecting these two things so we get on two different trains of changing them. It's interesting that, Jared, your version and David's version
Starting point is 00:39:53 is essentially not the same, but it's very explicit. Like you were prefixing JS and David's solution is reusing the concept of, of data attributes. And again, being explicit of saying this is different. This is not your normal class. It's for a special purpose.
Starting point is 00:40:14 Yeah. I think it's, it's coming from the same motivation, right? Like we want to be able to read a piece of HTML and know what it does. We don't want it to sort of just magically have things happen to it because far, far away there's some JavaScript class that declares an event handler that just happens to match this thing.
Starting point is 00:40:32 We want the explicitness and we want to be able to read it. I think that's just good code practice. So whether you do it one way or another, as you found, there's just a clear motivation to solve that problem. Yeah, and I think it was trying to get back to something that we lost when we went from writing your click handlers right there in the HTML, which is decidedly way too low level to be in your markup to now we're going to put everything into jQuery click handlers or what have you, is that we lost that connection. And now there's a lot of people rightly saying, hey, this is actually a step backwards because now you have like random things happening that you don't know about. There's no connection in the code. And so this kind of bridges that gap
Starting point is 00:41:21 and puts a nice, happy nice happy medium in place. Which really comes back to why are we doing stimulus? And why aren't we just picking an existing framework that's out there? There's certainly plenty of them in JavaScript land already. And I think some of it is because I just saw regressions. I saw that we took certain steps forward in certain domains with this new set of JavaScript frameworks. And then we took huge steps backwards in all sorts of different ways that apparently people just didn't care about.
Starting point is 00:41:53 And that's fine. I mean, we don't all have to care about the same things, but I cared about those things and I couldn't live with those regressions. So stimulus is a way to sort of not take those regressions, get back to, in some ways, a simpler time, which is, I mean, it's always dangerous once you get into arguing what's actually simpler and what's not simpler. Because a lot of it is tied up into, exactly. First of all, good old days, right? Good old days were often not that good. And second of all, just that we have different applications
Starting point is 00:42:25 and they work in different ways. If you're trying to make sort of this very intricate UI with tons of related things and blah, blah, blah, then maybe these heavy frameworks do make sense. If you're trying to make an application like Basecamp or GitHub, they don't make sense. And they are overly complex for what we're trying to do. And I just felt like there was an underrepresentation of frameworks that were trying to tackle the
Starting point is 00:42:54 class of application that GitHub and Basecamp finds itself in, which is not a small class. I would argue, in fact, that it is the larger class class and it's been severely underserved by this um recent advent and explosion of javascript framework that all focused on the same paradigm that the server side was now just tasked with producing json and then you would have some client side engine that would take that json and turn it into html build up a DOM, whether virtually or otherwise. And all the frameworks are just the same, right? Which is why I was sort of struggling a bit when there's such furious wars between like, oh, are you using Vue or are you using React or using Angular or using whatever? If they all come through the same paradigm of server-side generated JSON that's then dynamically translated into HTML.
Starting point is 00:43:46 I mean, come on, guys. It's the same idea, right? Like we're really furiously arguing about the small details. Stimulus provides a completely different paradigm, a paradigm where the server continues to create the entire HTML document. And then we sprinkle this remaining behavior that we need onto this through a progressively enhanced approach. But even when we do dynamic stuff, so we have stimulus controllers, for example, that will trigger a behavior on the server side. What the server side will return is a fragment of HTML. We use HTML as the transport protocol very rarely, although sometimes we will use JSON to do it. So when we want to update a part of the page, we ask the server side, hey, can you give me this fragment of it?
Starting point is 00:44:32 Which allows wonderful things like fragment reuse, which if you're familiar with Rails, we call those partials. And the fact that you can use the partials, the fragments of the HTML, both to render the initial version of the page and the subsequent updates is a huge step forward. That's interesting. I'm curious about this. I know that in Ruby code, David, you like to remove comments and rewrite code or replace comments with more readable code. And in your process of evaluating Basecamp and looking through things of this transition to stimulus, I'm curious how much of that happened in your code.
Starting point is 00:45:11 How many comments were joyously removed in replacing with this prototype version that you created? A fair amount of it. And I think that that is exactly the attraction to adorning the HTML with these very explicit tie-in with how things are called because when you have a button that says it has a data action where if you click this button we're going to call greet the greet action on the hello controller that's incredibly self-documenting you do not need a comment, a code comment to
Starting point is 00:45:47 explain what's going on. And on the controller side, the same thing, right? When you have a declaration of action methods up front, you don't need to comment on how those are hooked up. You're relying on the conventions that stimulus affords you. And those are already documented in stimulus. So we can really cut down on the amount of needless documentation that we need in our application code, which for me, whenever you have copious amounts of code common, it usually tells me two things. Either that you wrote convoluted code, that's probably the most common. Two, that you have a set of conventions that you're just still waiting to extract.
Starting point is 00:46:28 And then once you extract these, you can remove all this repetitional commenting. And these are sort of the driving motivations for why we want to get rid of them, why they're code smells. I mean, in some rare cases, what you want to do is actually just counterintuitive. And sometimes it's basically around browser bugs or something else. In some rare cases, what you want to do is actually just counterintuitive.
Starting point is 00:46:52 And sometimes, especially around browser bugs or something else, you're doing something that does not make sense if you just read it. And you need a code comment to explain, you know what, that's because IE Edge does something stupid here. And this is why we need to do this monkey dance to make it happen. But even in that case, I often find that you can still encapsulate that monkey dance in a method that succinctly explains that it's because Edge or Safari or Chrome or whatever is doing something that you need to have special consideration for. This episode is brought to you by Gliffy. Gliffy is the easiest way to visualize any idea. In a world where it's possible to draw a circle in the cloud
Starting point is 00:47:36 or put a square to a circle with some text in it, it lives a tool with over four and a half million users who easily diagram every single day online or directly in Atlassian using Confluence or Jira. And in this segment, Craig Cockrell, product design lead at Plastic, shares how his team lives and dies by Gliffy. For me, using Gliffy is really nice just because I'm able to really not have to worry about the tool as much. I can sit here and really focus on what I actually
Starting point is 00:48:05 want to accomplish. The way that I've described it to other people in general is it's something that's very hands-on. It feels as though you're really using very material objects and rearranging them on the fly and making that movement from taking this screen and moving it towards the end or reconfiguring that flow. It's not something where you really need to feel the pain of going through that. It comes so naturally that, you know, the tool is almost secondary. And what I'm trying to focus on and get done is the primary goal.
Starting point is 00:48:34 You know, ideas live or die on the diagrams that people create in Gliffy. If you're not creating that fidelity, it's something that it's very easy for that to just literally fall off to the wayside, you know, within the company here at our core, a startup, right? People have a lot of ideas and they have a lot of things, but there's obviously gaps in communication and without something to actually bring to people and bring to the
Starting point is 00:48:54 table and show that you've done some level of work, you've done some sort of background in a gliffy diagram is one of the best things that anyone has ever brought to any sort of product inception meeting or anything like that. And that is truly where we can start that collaborative process without that that conversation doesn't happen the right stakeholders don't get involved and at that point you don't have anyone rallying behind you and without you know the group rallying behind a certain project it just doesn't happen when anything begins it's so important that those individuals open Gliffy, in Confluence, get in there, start working, and just get it started. It's just something that allows a canvas for us to create. You can try Gliffy today for free, online or in Atlassian, using Confluence or Jira.
Starting point is 00:49:38 Start building ideas today with your team, and if you don't have any ideas to make, draw a duck, set it as your desktop wallpaper. Get started at gliffy.com slash changelog. All right, David, so one of the, you said what you saw was, you know, a lot of regressions and maybe even sidesteps in certain cases. One of the things I remember back in the day when Backbone.js first hit the scene, because this was one of the very first, you know, front-end frameworks that said, specifically, they said, get the state out of the DOM, right? Get it into JSON, get your state out of the HTML. And that was a step. And everybody started doing that in different ways. And so we became, you know, completely
Starting point is 00:50:37 detaching the front end and the back end. And like you said, Stimulus offers really a different opinion or a different way of going about building applications than a lot of the other front-end frameworks out there. And one of the things that it says on the homepage is state is stored in the HTML so that controllers can be discarded between page changes but still reinitialize as they were when the cached HTML appears again. So that's definitely a big difference from other things out there. Can you tell us about how that state is stored, how you deal with change? I know you mentioned a little bit during the last segment, but let's go a little bit deeper into how that all works. Sure. So we store state in much the same way that we declare the targets and the controllers and so on through data attributes. And we basically just set these data attributes on the usually the root element of that controller. And that stores the usually minimum amount of state like i think one of the reasons um backbone and other frameworks have argued for extracting state into something else is because maybe they they had a ton of it and
Starting point is 00:51:53 we try not to have a ton of it we try to have very little state between uh or within the the dom itself but just enough so that you can reinitialitialize a controller and it can come back to the form that it was. For example, a state could be, we have a collapse controller that allows you to click a certain element to open or close another element, right? You know, like show more or see less or whatever. And the state of whether that is open or closed is something you can store in the DOM. In that particular case, oftentimes the state is actually just an application of the classes. Classes provide usually most of the state that we need. For example, for the collapse example, we will apply a hidden class when the element is closed, and we will remove that hidden class when the element is open.
Starting point is 00:52:50 So that right there will store the state in itself. We try not to duplicate or create a shadow state of what the DOM already has, because we're trying to enable you to get HTML from anywhere, right? That most of the time, this HTML is coming in the form of the initial render, and the controllers simply have to take that initial render and instantiate themselves based off that. And then if you have other updates, it could be WebSocket updates that you have a WebSocket channel that inserts new HTML into the DOM. When that new HTML is inserted, it needs to include its own state. We don't have something else to also pass that state along with.
Starting point is 00:53:34 As I said, we use HTML predominantly as the transport layer, not JSON. So the transport layer has to include its own state, and that's what we found. This is actually a nicer way of doing it. And then just the fact that we go back and forth between pages, we're using this together with Turbolinks. And Turbolinks stores a nice cache of the pages we've been switching between. So if you have controllers that have been mutating the DOM,
Starting point is 00:54:02 usually just by adding CSS classes or whatever, Turbolinks will remember the state of that when you go from one page to another. So we get to sort of keep that state alive through the Turbolinks cache. And that's adequate and actually a useful, I think, constraint in most cases to not go hog wild with a whole bunch of intricate state. I suppose it works just fine without turret links. You just don't get the advantage of the fast refresh. You get a full page reload. Yeah, and you just got to be a little careful with those full page reloads and what the browser actually ended up caching,
Starting point is 00:54:43 whether it ended up caching the final version of what the DOM looked like, or it'll reinstate it from scratch. That's just Turbolinks helps a little bit there in terms of making it more fluid and making it easier to keep that state cached. So were there specific changes that went into Turbolinks to support this? I know you call it a one-two pack punch or something like this. I was wondering if that just happened, they just paired well nicely, or if Turbolinks to support this? I know you call it a one-two pack punch or something like this. I was wondering if that just happened, they just paired well nicely, or if Turbolinks required some specific upgrades or enhancements to actually support stimulus natively. It didn't because we were already basically writing stimulus before we were writing stimulus,
Starting point is 00:55:19 right? Like this approach of using progressive enhancement and storing state in HTML and using HTML as a transport layer. That has been our pattern and our paradigm for a long time. And we built Turbolinks originally with that paradigm in mind. So stimulus is basically just an encapsulation of that paradigm and packaging it up in a nice way. And that was really the missing second punch to Turbolinks that we would pitch Turbolinks to someone like, hey, this is this wonderful thing that can actually cut out like 80% of all this dynamic behavior you're doing because it'll speed up the page changes to such a degree that you don't need anything else. There's a lot of dynamic behavior we're doing
Starting point is 00:55:59 for performance reasons because it feels too slow to do a full page change that you no longer need when you're using turbolinks because the page changes are really fast so you can just send the whole page again even though you're making a relatively small change in a lot of cases but then there's still the last 20 percent where you didn't want to do that right like you had some small change like a collapse show thing as we just talked about it It's a little excessive if showing or hiding, which is basically just applying or not applying a CSS class to an element, required a whole round trip to the server and sending down all the HTML for a whole new
Starting point is 00:56:34 page just to apply a single additional class. That doesn't make sense. That's not proportionate. And it's not going to be fast enough to feel really good. So that was this missing gray land, the last 20% of behavior, where we kind of just waved our hands and said, have you looked at mutation observers, and then left it as an exercise for the reader, which was actually a fairly large task for someone to do. So I could see how not having a clear answer for that last 20% held back Turbolinks in some ways. So I'm really happy that we now have stimulus to provide 100% of the answer for applications like Basecamp.
Starting point is 00:57:11 And if you want to write them in this way, you now have all our tools, right? Like there's nothing hidden under the carpet here, right? Everything that we use to write Basecamp the way it is today is open source packaged up as an easy to use library or framework. And the story is now complete. And I think that that's really important that if someone is looking at their application and they can't visualize how they're going to solve this specific part of it or this specific feature, it's hard to gain adoption.
Starting point is 00:57:39 I think Turbolink suffered for some time with that. It also suffered for other reasons. For example, this notion that apparently it was hard to understand the concept of a persistent process and that you couldn't just drop in any jQuery plugin that was written with the idea of every page change blowing the process and the instantiated application away even though that was exactly the model that people have been following with single page applications and the heavy frameworks right like they all run in a persistent process where every right click of a link is not a full reload but for whatever reason i think a lot of people just saw like hey i should be able to just use triple links and any odd jquery plugin that I can find on the Internet. And those things need to just magically work together out of the box. And they sometimes just didn't, right?
Starting point is 00:58:30 You had to do special considerations to deal with the fact that Turbolinks does not change the full page, right? It gets a whole HTML document, but then it does the updating of that document in process. And it keeps the state of the JavaScript around and it keeps the state of the javascript around and it keeps the interpreted css around and that's where it gets its super speed its turbo speed so at base cam exactly at base cam we just didn't use a bunch of javascript or a bunch of jquery plugins we wrote most of our code yeah um that we needed ourselves and sometimes we used used some jQuery plugins and we just altered them a little bit since they were compatible with Turbolinks. And that never seemed like such a big deal to us because the benefits that we got back were so monumental. And what it allowed us
Starting point is 00:59:16 to do, especially in terms of the majestic monolith and applying a simple application that was automatically updated across five different platforms, which is such a huge win that was automatically updated across five different platforms which is such a huge win that was really hard for us to imagine that anyone would look at the small changes or concessions that you have to to make to get those wins and go like oh yeah that's not worth it so anyway i mean yeah turbolinks and stimulus they're frameworks we're writing for ourselves. I'm doing these things because we need them in Basecamp. And when someday the day is going to come when I write Basecamp 4, I want them to be available in packaged and clean form. So I can just use these frameworks off the shelf and get on my merry way. And if someone else ends up using it,
Starting point is 01:00:01 that's great. And if not a lot of people end up using it, that's also great. And we will continue to do it. It's sort of the same approach I have with Rails. When I originally wrote Rails, I wrote all of it, right? I needed a way to talk to the database. Well, I wrote ActiveRecord. I needed a way to render templates. Well, I wrote ActionView. So at Basecamp, we have a tradition of writing our own tooling. And then we share our tooling more out of sort of gratitude to the rest of the community for the tools that we do use. And just because that's a nice thing to do. And sometimes it ends up taking off, like as in the case of Ruby on Rails, and we get some benefits from that. And if it doesn't take off, that's also fine, and we get to use them.
Starting point is 01:00:47 I think that's really a sort of ambivalent or distant relation to the open source process, that we open source because we can, and because we like it, not because, oh, it has to gain adoption. Right. Just hypothesizing a little bit about Turbolinks, because I've been around, I think, for the Right. That problem with existing jQuery plugins and the fact that Turbolinks was such a plug-and-play aspect of a Rails application, you could literally just comment it in or out and it would or would not do everything for you
Starting point is 01:01:34 in terms of Turbolinks itself. It was so easy just to flip it off. Pun not intended, but perhaps maybe it should have been. So easy for people to just use Turbolinks as the scapegoat. It'd be on. This JavaScript issue doesn't happen. Oh, it must be Turbolinks. And so it just got a bad name right off the bat
Starting point is 01:01:54 just because of the existing ecosystem it came into. And then it's kind of like the Siri situation. People just don't, you know, it gets this reputation up front and then over time people kind of just naysay it or don't give it a second look. But maybe through stimulus, people will give TurboLynx a second look. Maybe not. But like you said, you're ambivalent to it. Well, I think also part of it is you have to understand what it's doing for you, right?
Starting point is 01:02:20 And I think perhaps that was the drawback of having it be so easy to turn on and be included by default is that if you don't fully understand the benefit that you're getting, you don't understand the tradeoff. And if you don't understand what benefits you get, any cost is too high. If I perceive the benefit as nil or nothing, then if I just have to pay just a modicum of work myself to get it, I'm going to say like, that's not worth it for me. And I think we're perhaps getting to the point where more people are realizing that using these heavy duty client side frameworks, oh, wait, they also have costs. And they also have, in many cases, towering complexity. And I think we're getting some veterans that are coming out of that process that go like, you know what, if I'm going to build another thing, I'm not going to do it like this again. That was just painful.
Starting point is 01:03:13 And I think that pain is exactly what we try to address, right? And until you've suffered that pain, I don't think you can fully appreciate the salve that we are offering, right? The bandage that we're offering, which in many ways was the same way that Ruby on Rails came to be, that there was so much pain that a lot of people had experienced using Java frameworks or PHP without any frameworks, that they were very in tuned with the pleasure that Ruby on Rails would bring them because they knew the pain. And I think until you know the pain, you don't have space in your brain to appreciate or even properly evaluate the solutions to it. So I think everyone should go and build a full application in the heaviest duty of JavaScript frameworks, regardless of whether their application warrants it, just so that they can suffer through it on their own skin and come out scarred and
Starting point is 01:04:09 battered on the other end and go like, eh, you know what? Maybe there's a better way. That's the bitter and the sweet, right? You can never really understand the sweet goodness of the chocolate bar unless you've had that nasty piece of candy after dinner or whatever. Like, you got to have the bitter to enjoy the sweet. That's right. Yes. And I think that that goes for all sorts of learning. I think that's why lists of best practices, for example,
Starting point is 01:04:33 divorced from the pain from where they arose, often don't make a whole lot of sense if they don't stick. People aren't ready to internalize lessons until they've encountered situations that really demanded those lessons in flight. And I think that that's – I mean I think that's just part of the learning process, that you can't appreciate everything up front. I think plenty of people end up going off to college and they end up having all sorts of courses in philosophy or whatever. And they can't apply them to their experiences or where they are in life and they go like oh this is worthless like what's existentialism about like that i can't use
Starting point is 01:05:12 that for anything and then a decade later they go like oh wait a minute um let me hear what camus has to say about the meaning of life because they're a different station in life and i think there's a lot of technology that works like that, that it doesn't really reveal itself until someone has suffered through the long road. Some of that goes to teaching and documentation. And one of the things that we is very difficult to do through read me's and docs and even blog posts, blog posts are a little better,
Starting point is 01:05:41 but they're so hard to find over time is like, what were the circumstances in which this solution came to be and why does it exist? Which is some of the gaps that we try to fill with a change log and shows is conversations with the people to give that historical context because, you know, there are no panaceas, right? There's no silver bullet and all of these have trade-offs and all of these have reasons why they were created. And so if you lack that historical context, as somebody who's coming to a stimulus or coming to a React and just picking a tool off the shelf based on the readme,
Starting point is 01:06:18 and you don't understand the historical context in which those tools were developed and why they exist, then you're basically doing a coin flip and you don't know how you can apply it to your given circumstances. So it's tough. Like you said, sometimes you just have to live and learn. You have to just go through it and realize it. But I think we can work together to give these historical contexts to people. And so they're more equipped to make those decisions. And I think that's spot on. I think there's so much technology that's presented just as the how, not as the why. And it's that why that gives us the context to evaluate whether this is a good fit for us. Can we see ourselves in the person who developed the solution? Can we see ourselves
Starting point is 01:07:02 and their troubles in our troubles? And that was one of the reasons why when we introduced stimulus, we did it with a document called The Origin of Stimulus, which basically walks through, why did we extract this? Why did we make this? And tells the story of the Basecamp code and our journey of making a majestic monolith and how we use Turbolinks together with stimulus, why the concepts make sense, which what are the problems as we talked about here, right? Like the problem of using CSS classes for targeting it's brittle. It's all these other things. It's not just like, Oh,
Starting point is 01:07:39 here's how to do that. Right. And I think that that's often missing. And I think sometimes people sort of evaluate things from the wrong perspective. One thing I've heard a lot of times is like, oh, I want to use React because Facebook is using React. So it's got to be good enough for me. Right. Right. And I've heard that with a lot of other pieces of technology, big companies using X. Thus, it must be good enough for me. I actually think it's often the exact opposite. A lot of the patterns and even outright technologies that large companies use are the worst thing you could pick when you're just starting out or if you're a single developer or
Starting point is 01:08:16 small team, because these things are designed to work with much larger teams and much larger companies with all sorts of different considerations and specializations and a stomach for a different level of complexity when you're trying to serve a billion and a half people um you just have different problems than what we're trying to solve at base camp we're trying to solve sort of servicing a few million people at the most right and different orders of magnitude and the correct and applicable patterns and practices that are relevant for someone trying to solve for a solution space of a few million people or less, just very different from the kind of people like Facebook, who have tens
Starting point is 01:08:58 of thousands of people working on the product and are trying to solve for a billion and a half. And I think sometimes people just get enamored with this, oh, I wish I was Facebook. So if I just start using their tool set and their mythology, maybe I'll become Facebook. No. Do you know what? If you looked at any history of actual Facebook, do you know what their code original looked like when Zuckerberg wrote it? I don't think there's any of those practices left anymore at the company, right? Because they evolved and they turned
Starting point is 01:09:27 into something else. But if Facebook had started out with the heavy-duty patterns and practices and methodologies that they're using now, if Zuckerberg had had to do all those things as just developer one, Facebook would never have happened. That's right. I have a counter to that, though. Twitter used Rails. And many people use Rails. So I think Twitter is a great example, a great scarecrow, a great reminder that there's so much more than technology
Starting point is 01:09:58 to whether someone fails, even technology-wise or not. Twitter, in the early days of the fail whale, blamed Ruby on Rails and its trouble because it was much easier to blame an external vector like Rails than their shitty architecture for why the site kept falling over. And then just recently, a few days ago, Twitter or some former executive from Twitter threw an article in Vanity Fair blamed Ruby on Rails on the fact that Twitter, 10 years into its existence, has still not dealt with harassment and abuse in a proper way on Ruby on Rails, which is just wonderful, right? Like it's a wonderful anecdote of how humans are so desperate
Starting point is 01:10:45 to diverge and deflect blame and accept responsibility for their own actions. And they're just trying to find any scapegoat. It's all your fault, man. Yeah, exactly, right? If you hadn't released Ruby on Rails, they would have never had this problem with harassment. And actually, that is true, right?
Starting point is 01:11:02 That is actually true in some sense, because maybe Twitter would never have existed, or it would never have taken off, or it would never have gotten done in time, or they would have run out of money or something else. So in a way, I think Ruby on Rails is implicated in the harassment problem at Twitter, because Ruby on Rails helped Twitter get started
Starting point is 01:11:18 and helped Twitter get off the ground. The fact that maybe it's been 10-plus years and they've still done so poorly at addressing the fundamental problems of harassment and abuse on the platform, maybe that blame falls elsewhere. But anyway. Let's move into something, I guess, a bit more promising. So you've had your hand in, obviously, writing frameworks. We know that. You do some great writing on Signal vs. Noise.
Starting point is 01:11:46 You've got a podcast. You've written books. You've done all these. You've raced cars. You got kids. You're like everybody else, right? You got all these cool things. But next up is YouTube for you, right? You got this cool new channel. Maybe not everybody's heard about yet, but I've been enjoying it. And one thing I think is pretty interesting is that you get this chance to essentially sit down with you and look through the Basecamp code base. And you're just sharing all the reasons why you've done what you've done. Can you take a moment and just kind of share what your plans are with that channel? Sure.
Starting point is 01:12:15 So the channel is called On Writing Software Well. And it's just just me opening up an editor and taking a topic that could be testing or callbacks or whatever and showing how we use that in Basecamp and showing how we use Rails and use Ruby to solve the problems. And what I wanted it to feel like was if I sat down with another programmer and we just looked through some code together. I always love doing that because I find that many programmers
Starting point is 01:12:45 when they're talking in the abstract about code and patterns and so forth, they have these fierce arguments. No, this is the wrong way of doing it. This is the right way of doing it. And then if you sit down with them and you look at actual code, you end up agreeing way more often than not because the pressures and the concerns of a specific piece of code guides most reasonable people in a similar direction, at least when they have somewhat of a shared background and experience. There may be functional programmers who are like, oh, anything object-oriented or side effect Latin is wrong and whatever, and you're not going to find common ground with them,
Starting point is 01:13:21 perhaps. But for anyone who exists in the same paradigm and somewhat of shared beliefs, if you look at concrete code, we end up sort of liking the same things a lot of the times, a lot more often than if we just argued about it in the abstract. And this is one of those lessons that I've learned time and time again. Ruby on Rails back in, I think, 2009 merged with another Ruby framework called Merb. And Merb was born for a lot of different reasons. And some of the reasons were that the people behind Merb cared about different things than what I cared about. Not that I actively didn't care about them.
Starting point is 01:14:01 They just weren't top of mind. There were some extensibility concerns that they had and some performance concerns that they had. And we thought we had these fundamental underlying philosophical differences about how to write a framework in Ruby. So I sat down with Yehuda Katz in particular, who was one of the guys involved with Merp at the time. And we had these fierce debates when we were just chatting in Campfire. And then we sat down and looked at the same piece of code and went, oh yeah, we believe the same thing. And we're like, wait, what? We were just arguing our heads off in opposite directions.
Starting point is 01:14:35 And then we looked at a piece of code together and we came to the same conclusions. And I've done that so many times now that I believe that that is really the primary way you should be arguing code patterns and principles is by looking at actual real production code and doing A-Bs. Let's write it your way. Then let's write it my way. Then let's see if there's one of the other ways that's the best or more likely that there's a combination of the two ways that turned out the best that we both like. And I find that that happens just all the time, right? So I wanted the YouTube channel to have that feel
Starting point is 01:15:08 as though we were sitting down at the keyboard together and looking at code together and coming to similar conclusions. That doesn't mean, I mean, you're not going to just, everyone is not going to sit down and watch these videos and go like, oh yeah, I would have written it exactly like David would have written it. But at least if you hear again, the why,
Starting point is 01:15:23 why we wrote it that way, how we weighed the trade-offs and came to certain conclusions, you'll understand why we did it the way that we did. And I think that that understanding is often sorely missing when people are talking programming and talking shop. And that's why they get, the arguments get so heated, right? We start having these violent disagreements that in many ways are completely unnecessary or completely unjustified by actual code. And it's really, it can't be solved and it can't be addressed just by looking at example code. It can't be addressed by the stylized, idealized version of what programming looks like, because until you have all the real constraints and pressures of production code, you're not taking all the complexity into consideration. And
Starting point is 01:16:09 oftentimes, that's exactly what tips the scale as to whether to go one way or the other way is to look at the real code, right? For example, I did an episode on globals. Rails 5.2, which is just about to be released, has a new encapsulation of globals for dealing with things like current user and current account within the sort of lifecycle of a single request. And if you just sat down and had an abstract conversation about globals with a programmer, most programmers would say, well, I learned or I heard or I know that globals are considered harmful. Why are you using globals? Globals are terrible or I know that globals are considered harmful. Why are you using globals?
Starting point is 01:16:47 Globals are terrible. Don't use globals. Are you a bad programmer? Are you terrible? What's going on here, right? And then you sit down and like, yeah, all those things have strains of truth in the aspects that globals are dangerous and you do need to be careful.
Starting point is 01:17:01 But hey, let's look at this code. Let's look at how much simpler and easier it actually becomes to understand once we use a global, right? do need to be careful. But hey, let's look at this code. Let's look at how much simpler and easier it actually becomes to understand once we use a global, right? It's not a thing you should use all the time and in all circumstances, and you can certainly get carried away with it. But in this particular instance, using the feature on this particular aspect of the code, it gets better. This A is better than that B. And I think that those are the sort of concrete trade-offs,
Starting point is 01:17:31 as I said, that are really just fascinating. And I think open people's minds much more than just a blog post that says, global is considered harmful. That's one thing I've really appreciated about this series with you is that you explain your preferences. And then you look at the code and you know, your preferences and then you look at the code and you say, this is why I'm breaking my own rule. This is why I'm putting these methods out of order in the private method rather than, you know, as a table of contents like you normally would. This is why, because it reads better. So I'm willing to trade off and, and you go against
Starting point is 01:18:03 the, my typical grain for these reasons. And it's like you kind of get a chance to step into your mind, watch how you program an actual application called Basecamp. You're looking at actual Basecamp code. I think it's a pretty interesting concept, and I'm glad you're doing it. That is really, I think, the pivotal thing, the nugget, the justification of it. The fact that there are all these principles and patterns and best practices of how you should write software. And in isolation, they all make sense.
Starting point is 01:18:31 But when you write a real application, usually all of them disagree. There'll be one pattern that tells you to do things this way, and then there'll be a best practice that tells you to do things another way. And you have to weigh these things and consider which one is more important in this particular instinct and which one will i put more weight on and that's where the wisdom is hidden i find that a lot of programmers apparently seem contented to just learn the recipes right to just learn like oh i can recite all the patterns i can recite solid i can recite solid. I can recite law of the meter. And then they don't really know what to do when these principles are in conflict with each other. And that is really where actual code is written.
Starting point is 01:19:14 It's written in conflict. It's written under one pattern and one consideration pulling in one direction and another pulling in another direction. And you have to carefully weigh, and sometimes subtly so um which you're going to put more emphasis on yeah let me just uh quick i agree with everything adam said about the show quick uh suggestion and or feature request for upcoming and this might be a little bit harder for you to organize but it'd be cool if you would sit down with sam or with javon or somebody who's somebody who has a different opinion about even Basecamp code and you guys could talk through a refactoring or talk through things where it actually is a dialogue.
Starting point is 01:19:51 Might be an interesting alternate style format for that show. A pair of programmers. Yeah, I'd love to do that. And I think that is basically what I'm trying to do, right? Like I'm having a dialogue somewhat with an imaginary programmer sitting next to me and the two minds of my own in my head. I've produced five of these episodes, I don't know, two hours of content or so on
Starting point is 01:20:15 in a week. The reason I can do that and the reason I can churn these things out is because I do one take and I just flip on my browser, I load up a couple of tabs of code and then I'll just freewheel it. And that is crucial to why this is happening. If I had to put in the sort of diligence and preparation work that perhaps it would take to include multiple participants, I just couldn't do it at this velocity and perhaps it'd be harder for me to maintain the stamina to do it at all.
Starting point is 01:20:46 And I think that's why it's kept me back from doing this before, because I thought, like, it's going to be a big production, it's going to be a big thing. No, I mean, most of these episodes have, like, literally five to ten minutes of prep work where I'm picking out the files I want to talk about, and then I hit record, and then I push stop when I'm done, and then that's it
Starting point is 01:21:05 yeah it is a trade-off in a good way it's a pretty simple production process for you I think production process is even a very fancy word for I mean I'm hitting record and then I'm hitting stop and that's that's it there's not a lot of post-processing or or second takes gotcha is there anything else to share about the future of stimulus, maybe the next version of Rails before we close out? Any sort of planned convergence? I know that Rails does a lot of generation in terms of scaffolding. Any plans of stimulus being baked in and HTML going down the pipe
Starting point is 01:21:37 with data attributes? Anything left unplugged? What is coming is greater integration with Webpack. So we already have wonderful integration with Webpack through a gem called Webpacker, which gives you a way of using Webpack in a Rails application in an easy way. And Stimulus is made for that.
Starting point is 01:21:58 Stimulus is made for use with Webpack. You can use it outside of that. There is a compiled version. You can do that. But most people, most of the time, will use it with Webpack or something similar. And that's the direction we're moving towards. We're moving away from generating or compiling JavaScript through the asset pipeline. The asset pipeline goes all the way back to, I think, 2008 or something, where we had to build our own tooling for compiling JavaScript because there just wasn't a good ecosystem around JavaScript itself to do it.
Starting point is 01:22:32 Well, that's totally different now, right? There's actually multiple competing ways of compiling JavaScript, and many of them are very fine, and we've decided to pick Webpack as the default. And we should take fuller advantage of that because that's where most of the development is happening. So the asset pipeline can kind of step back now that the job of compiling JavaScript is so eminently handled by the JavaScript community itself and say, you know what, I'm just going to hand this responsibility over.
Starting point is 01:23:03 So Rails 6, as we're coming up upon after the real release of rails 5.2 is going to figure out a way to make that blend beautifully and have an emphasis and a focus on webpack out of the box which then also means a focus on making it super duper easy to use stimulus out of the box because you'll basically just be able to say Rails new my app dash dash webpack equals stimulus and we'll set you up with a default scaffold for using stimulus. Even though there's not even that much scaffolding to set up but I find oftentimes what keeps people back
Starting point is 01:23:38 and stop them from using something is just getting hello world. Just getting all the things wired up and I think the joke, particularly in the JavaScript community, is that you have to spend two days setting up your compilation pipeline before you even get to Hello World.
Starting point is 01:23:53 So Rails certainly wants to assist you with that, so that you can just run one command and you can see Hello World is already there and then you can start filling in with your own application code. So that's one area that we're focused on. And just mending relations, perhaps, in some ways with the JavaScript community. I think I've certainly had a contentious relationship
Starting point is 01:24:12 with JavaScript for many years because I thought ES3 was a kind of shitty language, to be quite frank, for this kind of style, object-oriented focus that I wanted to write and that the ecosystem around interfacing with the dom and the differences between browsers just made it a miserable experience well um lo and behold 10 years makes such a difference and things are different now and and i've come
Starting point is 01:24:37 to really enjoy javascript in in many of its forms and stimulus is certainly one of those forms so i'm just really excited to share that with the world and share a different paradigm as we've talked about from the json over the wire is the only way to go idea to say like hey do you know what html is actually a wonderful wire format and and we've used it successfully for what 30 years now and it still has legs in it and then some and it has clear advantages on productivity and other things. So let me promote that as an alternative path. I have no illusions that just because we promote this alternative path
Starting point is 01:25:12 that everyone will switch to it. I think there's tons of momentum, and deservedly so, around solution like React and elsewhere. We don't have to win total domination. I think development communities sometimes have this mistaken notion that it's all about market share and it's all about picking a winner. To me, there's just such wonderful beauty in the diversity of the web. any kind of implementation language that we wanted on the back end, that you could write it in Perl, Ruby, or AppleScript, and as long as it output HTML, the user's none the wiser, which just gave a rise to just such a wonderful diversity
Starting point is 01:25:54 that we could have people of all different inclinations and brain shapes find exactly the language and the environment that spoke to them. And I hope that everyone has the opportunity to find a language and an environment that speaks to them as much as Ruby and Rails has spoken to me. And I think that we can carry that into the JavaScript land in large extent now because of the advances with transpilers and so forth. And so should we with the proliferation of different paradigms. Well, David, thank you so much for your time today, man. I appreciate, you know,
Starting point is 01:26:29 your willingness to experiment, to dive into Basecamp and extract patterns and come out with what is not stimulus. And then, you know, your passion for open source to release it because you can and because you have gratitude back towards the tools that you've used. And we appreciate that about you. So thank you very much. Thank you. I can honestly say that it's entirely my pleasure. All right, that's it for this episode of the change log. If you enjoy the show, do us a favor, go on Apple podcasts, rate the show, tell your friends, tweet about it, whatever you got to do, share with a friend because this show is awesome and more people need to listen to it a huge thanks to our sponsors rollbar linode and our new sponsor glyphe and bandwidth for changelog
Starting point is 01:27:17 is provided by fastly so head to fastly.com to learn more. Aaron Monterings by Rollbar. Rollbar.com. And everything we do is hosted on Linode servers. Head to Linode.com slash changelog. Check them out. Support this show. This show is hosted by myself, Adam Stachowiak, and Jaren Santo. Editing is by Jonathan Youngblood. Music is by Breakmaster Cylinder. And you can find more shows just like this at changelog.com.
Starting point is 01:27:43 And also subscribe to our weekly email. Thanks for listening. Thank you.

There aren't comments yet for this episode. Click on any sentence in the transcript to leave a comment.