POPULARITY
Joël explains his note-taking system, which he uses to capture his beliefs and thoughts about software development. Stephanie recalls feedback from her recent RailsConf talk, where her confidence stemmed from deeply believing in her material despite limited rehearsal. This leads to a conversation about the value of mental models in building a comprehensive understanding of a topic, which can foster confidence and adaptability during presentations and discussions. The episode then shifts focus to the practical application of enumerators in Ruby, exploring various mental models to understand their functionality better. Joël introduces several metaphors, such as enumerators as cursors, lazy collections, and sequence generators, which help demystify their use cases. Episode on note-taking (https://bikeshed.thoughtbot.com/357) What we believe about software (https://bikeshed.thoughtbot.com/172) Ruby Enumerators (https://ruby-doc.org/3.3.1/Enumerator.html) Enumerator Lazy (https://ruby-doc.org/3.3.1/Enumerator/Lazy.html) Modeling a Paginated API as a lazy stream (https://thoughtbot.com/blog/modeling-a-paginated-api-as-a-lazy-stream) Solving a memory performance issue with enumerator (https://thoughtbot.com/blog/how-we-used-a-custom-enumerator-to-fix-a-production-problem) Find in batches (https://api.rubyonrails.org/classes/ActiveRecord/Batches.html#method-i-find_in_batches) Binary tree implementation with different traversals (https://gist.github.com/JoelQ/02f3ef9f61bebc7c8e5ea67d10ed92c6) Teaching Ruby to Count (https://www.youtube.com/watch?v=PHMOsTK1jSE) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville, and together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: So, what's new in my world isn't exactly a new thing. I've talked about it on the podcast here before, and it's my note-taking system. I have a system where I try to capture notes that are things I believe about software or things I think are probably true about software. They're chunked up in really small pieces, such that every note is effectively one small thesis statement and a paragraph of text, and maybe a diagram or a code snippet to support that. And then, it's highly hyperlinked to other notes. So, I sort of build out some thoughts on software that way. A thing that I've done recently that's been pretty exciting with that is introducing a sort of separate set of notes that connect to my sort of opinion notes. So, I create individual notes for public works that I've done, things like blog posts or conference talks. Because a lot of those are built on top of ideas that have been sitting in my note system for a while. Readers and listeners get to sort of see the final product, but often sort of built up over several months or even a couple of years as I added different notes that kind of circled a topic and then eventually got to a thing. What I did, though, was actually making those connections explicit. And so I use Obsidian. Obsidian has this cool graph view where it just sort of shows all of the notes, and it circles them with, like, connections between them where the notes connect. So, I can now see in a visual format how my thoughts cluster in different topics, but then also which clusters have talks and blog posts hanging off of them and also which ones don't, which ones are like, oh, I have a lot of thoughts on this topic, and I've not yet written about it in a public forum; maybe that would be a thing to explore. So, seeing that visual got me really excited. I was having a good time. STEPHANIE: Yes, I have several thoughts coming to mind in response, which is, I know you love a visual. I really like the system of, even if you have created content for it, like, you have a space for, like, thoughts about it to evolve. Because you said, like, sometimes content comes out of notes that you've been...or, like, thoughts you've been having over years, but it's like, even afterwards, I'm sure there will still be new thoughts about it, too. I always have a hard time finding a place for that thing kind of once I, I don't know, it's like some of that stuff is never really considered done, right? So, that is really cool. And I also was just thinking about an old episode of The Bike Shed back when Chris Toomey and Steph Viccari hosted the podcast called "What We Believe About Software," I think, is the title. And I was just thinking about how, like, if only we could just dump all of your notes [laughs] into some, you know, stream [laughs], and that would be really cool. If we ever do, like, an episode like that, that would be really fun. And I'm sure, you know, you already have this, like, huge bank of ideas [laughs]. JOËL: Yes. It is really fun because I build up...the thoughts are often sort of interconnected, and so they might have a topic, but they are very focused. So, I might have, like, three or four things I believe about a particular topic that cluster together. So, we could...and, actually, I have used, in the past, some of those clusters as initial food for thought for a Bikeshed episode. STEPHANIE: Yeah, that's really neat. I like this idea of a kind of just, like, a repository for putting down what you believe about software as kind of, like, guiding principles for yourself as a developer a little bit. I remember a piece of feedback I got about my RailsConf talk that I gave a few weeks ago, and someone said like, "Oh, you sounded really confident in what you were talking about." And that surprised me because I, like, didn't practice rehearsing giving the talk all that much [laughs]. It's because they had asked like, "Oh, like, did you practice a lot?" or something like that. And I think I realized that I, like, really believed in what I was sharing and kind of that, I think, was perhaps what they were picking up on. And even though, like, maybe the rehearsal of the presentation itself was not where I had spent a lot of time on, I had spent a lot of time thinking about what I wanted to share and just building up my confidence around that. So, I thought that was an interesting connection. JOËL: Yeah, you fully developed the idea. You kind of explored all the side trails, maybe a little bit on your own as well. You're on very familiar terrain. And so, that is a way of building confidence separate from just sort of memorizing a talk. STEPHANIE: Yeah, yeah. Exactly. JOËL: In a sense, I almost feel like that's a better sense of confidence because then you can sort of...you can roll with the punches. You know, if a slide is out of order or something, sure, it maybe messes up a little bit of the narrative that you're trying to say. But you're not like, "Oh no, what is this content?" You're like, "Oh yeah, this thing," and you can dive right into it. Somebody asks you a question, and you're not like, "Oh no, that was not in the script," because, again, you've sort of mastered your topic. You know the area as a whole, even sort of the blurry edges beyond the talk, and can react in a way that is pretty confident. STEPHANIE: Yeah. I still definitely fear the open Q&A. I've never done it before, but maybe one day I will be able to because I just, you know, know my topic so well inside and out [laughs] that I can roll with the punches, as you say. JOËL: Open Q&A is just...it's a roll of the dice. Sometimes, you get some really good conversation topics there, and sometimes, it's just a waste of everyone's time. STEPHANIE: I like that take [laughs]. JOËL: Maybe that should go into the things I believe about software. So, other than receiving feedback about your RailsConf talk, what is new in your world? STEPHANIE: Yeah, so I am wrapping up a pretty large project on my client work that we're hoping to release soon. And, in fact, it's actually being released along with a big announcement from the client company to their customers. Essentially, at a conference, they're going to say like, "Hey, like, we now have this new feature." And so, I think there's some hype generated around it. And this past week, we've been doing a lot of internal testing of the feature because there are a lot of employees of my client company who are, like, pretty big users of the product, which is cool because I think we're getting, you know, we have easy access to people who can give us good feedback. But I am having a hard time with being on the receiving end of the feedback and figuring out, like, what is stuff I need to attend to now before, you know, this big release? And what is stuff that is just kind of, like, general feedback like, "Oh, like, I wish it did this," but, you know, it turns out that that's not really what we were building? And how do I just kind of, like, accept that? You know, it's coming from a good place, but I can't really help them there, at least right now. And that's hard for me because I like helping people, right? And so, if someone says something like, "Oh, like, I wish it did this," or like, "Oh, that's kind of weird," I'm like, "Oh, I want to just, like, fix that for you right now [laughs]." And I suspect that a lot of other devs can relate to this, especially if, like, you know, you've been working on something for a little bit, and it feels...I'm just going to say it: it feels a little precious to me. So, what I'm trying to do today, actually, is not look at any of the feedback at all [laughs] and come at it tomorrow with a bit of a calmer vibe and be able to separate out, like, you know, I think all feedback is informative, but not all of it is useful for you at any given moment. Like, if there are bugs, then those will be my immediate priority. If there's maybe some small tweaks that we can make the feature just a little bit more polished, then I also think those are good. But then we are discovering a few things, too, about, like, what this feature is or could be. And I think those are the things that, you know, need to be brought into a conversation with a broader group and think about, like, is this the direction we want to go? So, that's kind of how I'm bucketing that feedback right now. JOËL: How do you feel about receiving direct feedback versus having something filtered through something like a product team? STEPHANIE: Ooh, that's an interesting question. Because right now we're doing, I think, a mix of both that I'm not sure that I really like. On one hand, when it's filtered, it's hard to get to the root of what someone is asking for. And oftentimes, like, it may not even include enough information after the fact to be able to come at it from a dev perspective. But then direct feedback, I think, is just a little bit overwhelming sometimes. And it can be hard to figure out what to pay attention to if you don't have that, like, input from a product team about, like, what the roadmap is looking like or where, you know, strategically their heads are at. So, one thing that kind of has emerged from this is like, oh, I was getting, you know, notifications for the feedback coming in. And what we did was set up a meeting [laughs] so that we can...maybe all of us can, like, scan it together ahead of time and then come at it with a little bit of context about what's come in but then maybe coalesce around the things that we feel are important. JOËL: Well, you'll have to keep us updated on how that plays out, and we can kind of hear what is the balance that ends up working well for you. STEPHANIE: Yeah, I hope so. I think this is actually maybe something that's a bit underexplored from the dev perspective, you know, that in-between stage of you're not totally done because it's not shipped to the world yet, but, you know, you're starting to get a little bit of that input. And what you do with that? Because I think there is some value in being engaged in that process. JOËL: So, we were talking earlier about this note-taking system that I use and sort of a renewed excitement that I have about it. And one thing that I did when I was going through and finding clusters of things that hadn't been written about was I found that I had a cluster of notes on different mental models that I had for understanding Ruby enumerators, not the enumerable module, but the enumerator object. And I decided, you know what? This would probably make for a good blog post. So, I drafted a blog post, and I've been thinking about this a little bit more recently. So, I've been really hyped about digging into enumerators because of that experience. STEPHANIE: Yeah, that's very cool. I have to say that I feel like I did not know a lot about enumerators and the API for them kind of before you brought this topic up, and I did a bit of a deep dive in preparation for us to discuss it. I feel like most devs, you know, work with enumerators via methods on enumerable without totally knowing that they are. So, I think that this would be a really interesting episode for people to be like, oh, like, I've been using this stuff, you know, the whole time, and now I can have a different perspective or just more insight on what they can do. JOËL: Before we dig into individual mental models, though, I want to think a little bit about the concept of mental models as a whole. Years ago, someone gave me advice to sort of pay attention to mental models, ways I think about the world or different code structures, different code approaches, and that really stuck with me. So, I've since been, like, kind of, like, collecting mental models. And, in a way, they're like a, for me, a bit more of a concrete way to look at a particular topic. So, I can say I'm looking at this particular topic through the lens of a particular mental model that helps me build more clarity around it. And if I have three or four, then I can kind of look at it from three or four different perspectives. And now, all of a sudden, I feel like I'm seeing in three dimensions. STEPHANIE: Whoa, the Matrix even [laughs]. That's cool. Yeah, I really like that advice. I think I'm going to steal it and start kind of suggesting it to other people because I think, in a way, on this show, that has come through a lot. And talking about things on the podcast has helped me develop a lot of my mental models. And I think we've done a few, like, episodes in the past about various ones we have for just our work because it's like, that's infinite [laughs]. But what I really have been appreciating is that mental models just need to work for you. As long as you're able to understand something, then it's valuable. And that has really helped me also, like, just get on the same understanding with others because the goal is not necessarily to, like, explain it the way that I would think of it, but figure out what would help them kind of develop their own mental model for understanding something, and, you know, kind of as long as we both feel like we have that shared understanding, no matter what lens it's through. And, you know, sometimes it's even more effective when we are able to share it. But I feel like, you know, you can still find ways to collaborate on something with a diversity of mental models. JOËL: Yeah, they're a great way to build self-understanding. They're a great way to sort of build understanding between two people. So, I'm a huge fan of the concept. And part of what I've been doing with my note-taking system is trying to capture those as much as possible. If I'm ever, like, trying to understand a complex topic and I'm like, oh, I think I've got a breakthrough here; I understand it; it's kind of like this, or you can imagine it in this perspective, it's like, write that down. That's gold. STEPHANIE: Very cool. So, Joël, would you be able to share some of your mental models for enumerator? JOËL: So, one way that I look at it is the idea that an enumerator is effectively a cursor over a collection. So, you have an array and a regular array; you're either in the middle of iterating through it using something like each, or you're not. You just have a collection of items. Enumerator introduces the idea that you're actually sort of at a position in the array. So, you're sort of focused on, let's say, the third item or the fourth item. You have a cursor there, and you can move that cursor forward as you sort of step through. But the really cool thing is you can also kind of pause and just pass that cursor on to someone else, and someone else can move the cursor a few steps further down the collection, pause, pass it on to someone else. And it's totally fine. Nobody has to, like, go through an entire, like, each iteration. STEPHANIE: Yeah. So, when you were talking about cursors, that got me thinking a little bit because I actually have struggled with that concept, especially when it comes to, you know, things code-related. Like, when I've had to work with database things and stuff, like, the idea of a cursor was a little, like, difficult for me to wrap my head around. And I was looking at the methods on enumerator, like the instance methods on enumerator. And one of them actually is what helped me develop this mental model. And I'm excited to see what you think. But there is a rewind method that basically rewinds the sequence back to its beginning, right? And what that triggered for me was a VHS tape [laughs] and just those, like, car-shaped rewinders for tapes back in the '90s. I don't know if you ever had one in your house, but I did. And I just thought that was such a cool method name because it was very, I don't know, it was just like a word that we use in the English language, right? So, the idea of, like, tapes, you know, like, cassette tapes or VHS tape kind of also it sounds like it matches well with what you were sharing, too, where it's like, I could pass, I don't know, maybe I, like, listen to a few songs on my cassette tape, and then I give it to someone else, and they can pick up where I left off. And yeah, that was really helpful in understanding, like, a marker of a position a little more than cursor was able to for me. JOËL: That's really interesting because now I wonder, like, how far we could push that metaphor. So, musical data is encoded on magnetic tape. Cassette tapes typically there are sort of two spools. You start off with all of the tape wound up around one spool, and then as it sort of moves across the read head, it gets wound up on sort of the, I don't know, destination spool. I guess you can call them origin and destination. And because of that, you can sort of be in a, like, partly read state where, you know, half the tape is on the destination spool, half of it is on the origin spool, and you have that read head that's in the middle, and you're just kind of paused there. And you can kind of jump forward in that. So, I imagine something like that in your metaphor is like an enumerator. Contrast that to imagine just a single spool, which is just we have musical data encoded on magnetic tape, and we wrapped it up on a spool. I feel like that's almost more like a regular array because you don't have that concept of, like, position, or being able to read parts of it or anything like that. It's just, here's some data. STEPHANIE: Yeah. While you were talking about the two spools, I was thinking about, like, part of what is nice about enumerator is that you can go forward or backwards, right? And that feels a little more possible with that two-spool metaphor [laughs], rather than just unraveling something, where you are kind of discarding what has already been read. JOËL: The one caveat there is that enumerators can move forward one item at a time. They can only move backwards by jumping back to the beginning. So, you can't step forward or step back. STEPHANIE: Yeah, that's fair. JOËL: You step forward, or you, like, rewind to the beginning. I think, in my mind, I was thinking a little bit more about this metaphor. And I think it's also just a metaphor for what's called the External Iterator Pattern. It's one of the classic Gang of Four Patterns, which is what enumerator, the object in Ruby, is an implementation of. I feel like I always see that in the documentation, like, oh, enumerator is an implementation of the External Iterator Pattern. And I just kind of go, what? STEPHANIE: [laughs] JOËL: Or maybe I kind of understand the idea of, like, okay, it's a way to, like, be able to step through a collection. But thinking in terms of a cursor or even your model as a cassette tape, I think that gives me a model, not just for enumerators, but then for better understanding that external iterator pattern. Like, I'm now not going to think of if I'm ever reading through the Gang Of Four book, or some other languages say we're an doing External Iterator Pattern, and I'll immediately be like, oh, that's a cursor, or that's a cassette tape. STEPHANIE: Yeah, very cool. I like it. JOËL: Another mental model that I have is thinking of enumerator in terms of a lazy collection. This is something that you tend to see more in functional programming languages, so the idea that you have a collection of potentially infinite length, or it could even be unknown length. But each element only sort of comes into being as you attempt to read it. So, it's kind of, like, a potentially infinite chain of Schrodinger's boxes. And you've got to open each of them to find out what's inside. STEPHANIE: Do you know what this reminded me of? Like elementary school math questions that were like, "What comes next in this pattern?" And it has, like, you know, the first, like, four or five values in a sequence or something. And then, you have to figure out, like, what the next value is. But then, in some ways, you know, I think it can depend on whether your enumerator is using the previous value to determine the next one. But yeah, it's like, you can't just jump ahead to figure out what the 10th, you know, value in this pattern is without kind of knowing what's come before it. JOËL: And sort of that needing to step through the entire collection, sort of one element at a time. STEPHANIE: Yeah, exactly. JOËL: I think a way that that concept is interesting, to me, is situations where a collection might be expensive, and you don't necessarily need all of it. So, you might have a bunch of calculations, but you can stop when you've hit the first one that succeeds or that matches a certain criteria. And so, it's not worth it to calculate the entire array of calculations if you're going to stop at the third one. And you could do that with some sort of, like, loop or something like that. But having it as a collection means you get to just treat it like an array, and you can call detect on it and do all the nice things that you're used to. It just happens to be a little bit more efficient in terms of not creating more data than you need to. STEPHANIE: Yeah. And I think there's some really cool stuff you can do when you start chaining enumerators with this concept of it being lazy evaluated. So, one of the things I learned in my deep dive is that when you are using the lazy method, you're able to chain enumerators. And they work a bit differently, where the default functionality is, like, everything in the collection gets evaluated through the first method, and then it gets iterated over in the second method. Whereas if you use lazy, I believe how it works is that, like, the first value gets kind of processed by all of the methods. And then, you get, you know, the output before moving on to the second, like, the next value. Does that sound right? JOËL: Yes. And I think that's where there's often a lot of confusion because there's sort of plain enumerator, and then there's a lazy enumerator that Ruby provides. A plain enumerator is a lazy list in the sense that items don't get evaluated unless you try to reach for them. So, if you have an enumerator and you say, "Just give me the first five items," it will do that. And even if the collection was 200 items long, the next 195 don't get evaluated. So, that's very efficient there. Where you would get into trouble is that plain enumerators are not lazy when it comes to traversals. So, any method that would traverse the entire collection, so something like a map or a select, is not going to be lazy because it's going to traverse the entire collection, therefore forcing us to evaluate each of the items in there. Whereas something like enumerable lazy will not actually traverse the collection when you do your map or you're selecting. It will wait for you to say, "Give me the first item," or "Give me the first ten items," or something like that. But you don't always need lazy. You really only need lazy when you're doing a traversal method. STEPHANIE: Okay. Cool, cool, cool. That makes a lot of sense. JOËL: I think a sort of spinoff metaphor that I have there is this idea of a lazy list. Another concept that, in my mind, is very adjacent to lazy lists is the concept of streams. And streams I typically think of them in terms of, like, files or networking, things like that. But a thing that you can do let's say you're working on data that's in a very large file, so big that you can't fit it into memory, a common solution there is streaming it. So, you don't load the entire file into memory and then operate on it. Instead, little chunks of it are loaded into memory. You operate on them, and then you release that memory and load the next chunk. So, you sort of work through that file in chunks, but you'd only have, you know, 1 line or ten lines or however big your chunk is in memory at a time. An enumerator allows you to do that with things that are not files. So, this could be a situation where, let's say, you're reading a lot of data from the database. You just have too many rows. You can't load them all into memory at once. But you do want to traverse through them. You could chunk that using enumerator so that every, you know, it loads 100 rows at a time or 1,000 rows at a time, or something like that. And your enumerator allows you to treat that as though it's a single array, even though, in the background, it's being chunked into pieces so that you never have more than a thousand rows at a time in memory. So, it allows you to do some, like, really nice sort of memory performance things. STEPHANIE: When would you want to use this over kind of something like batching queries? JOËL: So, I think ActiveRecord findinbatches does something like this under the hood. STEPHANIE: Oh, cool. JOËL: I don't know if they use Ruby's enumerator or if they sort of build their own custom extension to it, but it's built on this idea. STEPHANIE: Okay, that's really neat. I have another mental model that I wanted to get your thoughts on. JOËL: Yeah! STEPHANIE: One of the ways that I looked up that you can construct an enumerator, an infinite enumerator like we were talking about a little bit earlier, was with the produce class method. And that actually got me thinking about a production line and this idea that, you know, you have this mechanism for, you know, producing some kind of material or, like, good or something like that. And it's just there and waiting and ready [laughs] for you to, like, kind of ask for it, like, what it needs to do. And you can do that, like, sometimes in batches, right? If you are asking for like, "Okay, I want a thousand units," and then the production line goes to work [laughs]. But yeah, that was another one of those things where I'm like, wow, they really, I think, came up with a cool method name that evoked, like, an image in my head. JOËL: That's the power of naming, right? And I think it's interesting you've mentioned twice how going through the method names on enumerator and finding different method names all of a sudden, like, turned on a light bulb in your mind. So, if you're naming things well, it can be incredibly useful for users of your library to pick up on what you're trying to do. So, I want to circle back to something that you mentioned earlier, the idea of elementary school quizzes where you have to, like, figure out the next item in the sequence. Because that, for me, is very similar to my mental model: the idea that an enumerator is a sequence generator. So, instead of thinking of it as, oh, it's like an array or it's some kind of collection, instead, think of it as a robot that I can just ask it, hey, give me a value, and it will give me a value. And then, it will, like, keep doing that as long as I keep asking it for it. And those values, you know, they could be totally random. You can build one of those. But you can also have it so that the values sort of come from a sequence. It's not like an array where you're like, oh, I'm going to, like, predefine an array of, I don't know, the Fibonacci sequence, and when someone asks me for the third value, I'll just go and read that third value from the array. Instead, it knows the algorithm, and it just says, "Oh, you want the next value in the Fibonacci sequence? Let me calculate it. Here it is. Oh, you want the next value? Here it is." And so, thinking from that perspective helped me really come to terms with the concept that values really do get calculated just in time. It's not really a collection. It's an object that can give you new values if you ask it. STEPHANIE: Yeah, okay. That is making a lot more sense kind of in conjunction with the lazy list model that you shared earlier, and even a little bit with the production line that I was kind of sharing where it's like, you know, in this case, kind of, it's, like, the potential for a value, right? JOËL: Right, exactly. And, you know, these are all mental models that converge on the same ideas because they're all just slightly different perspectives on what the same object does. And so, there is going to be some overlap, some converging between all of them. I have another fun one. Can I throw it at you? STEPHANIE: Please. JOËL: This one's a little bit different, and it's the idea that enumerators are a tool to bring your own iteration to a collection. So, imagine a situation where you're building your own, let's say, binary tree implementation. And there are multiple ways to traverse through a binary tree. In particular, let's say you're doing depth-first search. There are sort of three classic ways to traverse that are called pre-order, post-order, and in-order traversals. And it really is just sort of what order do you visit all the children in your tree? Now, the point of a collection, oftentimes, is you need a way to iterate through it. And a classic solution would be to include enumerable, the module. In order to do that, you have to define a way to iterate through your collection. You call that each. And then, enumerable just gives you all the other nice things for free. The question is, though, for something like a tree where there are multiple valid ways to traverse, which one do you pick to make it the each that gets sort of all the enumerable goodies, and then the others are just, like, random methods you've defined? Because if you define, let's say, pre-order traversal as each, now your detect and select and all those are going to work in pre-order, but the others are not going to get that. So, if you map over a tree, you're forced to map over in pre-order because that's what the library author chose. But what if you want to map over a tree in post-order or in-order? STEPHANIE: Yeah, well, I'm guessing that here's where enumerator comes in handy [laughs]. JOËL: Yes. The approach here is instead of designating sort of one of those traversals as the sort of blessed traversal that gets to have enumerable; you build three of these, one for each of these traversals. And then, what's really nice is that because enumerators are themselves enumerable, they have map and select and all of these things built in. Now you can do something like mytree dot preorder dot map or mytree dot postorder dot map. And you get all the goodies for free, but the users of your library get to basically choose which traversal they want to have. As a library author, you're not forced to pick ahead of time and sort of choose; this is the one I'm going to have. You sort of bring your own traversal by providing an enumerator, and then everything else just kind of falls into place. STEPHANIE: Bring Your Own Traversal (BYOT) [laughter]. I like it. Yeah, that's cool. I can see how that would be really handy. I have not yet encountered a situation where I needed to get that deep into how my iteration is traversed, but that's really interesting. And, I mean, I can start even imagining, like, having an each method defined in these different ways, and then all of that being able to be composed with some of the other...just other methods. And now you have, like, so many different ways to perhaps, like, help, you know, different performance use cases. JOËL: Yeah, it can be performance. I often tend to think of enumerator as a performance thing because of its sort of lazy properties because; it allows you to sort of stream or chunk data that you're working with. But in the case of this mental model of the Bring Your Own Traversal, it actually is more about flexibility and having sort of the beauty of Ruby without having to compromise on, oh, I have to pick a single way to traverse a collection. STEPHANIE: But I really appreciate kind of this discussion about enumerator because this was previously, like, I don't think I have really ever used the class itself to solve a problem, but now I feel a lot more equipped to do so with a couple of the different kind of perspectives. And I think what they helped me do is just prime myself. If I see a problem that might benefit from something being iterated in a lazy way, like, being like, oh, I remember this thing, this mental model. Now I can go kind of look at the documentation for how to use it. And yeah, like, I don't know how I would have stumbled across, like, reaching for it otherwise. JOËL: That's a really interesting thing to notice because we've been talking a lot about how mental models can be a tool for understanding. But once you build an understanding, even though it's somewhat fuzzy, they're also a great tool for sort of recall. So, not only are you thinking, okay, well, this mental model says enumerators are kind of like this, or they function in this way. On the flip side of it, you can say, "Well, lazy evaluation problems are often enumerator problems. Like, streaming or chunked data problems are often enumerator problems. Multiple traversals are enumerator problems." So, now, even though you don't, like, fully understand it in your mind, you've got that recall where you can enter it, where you can come across that problem, and immediately you're like, oh, I'm dealing with multiple traversals here. I don't remember exactly how, but somehow, in my mind, I've got a connection that says, "Enumerators are a solution for this. Let me dig into that." STEPHANIE: Yeah, especially as an alternative to where I would normally reach for something...a more kind of common enumerable method. Because I definitely know that feeling of like, oh, like, I wish it could just, like, do this a little bit differently, you know. And it turns out that, you know, something like that probably exists already. I just needed to know what it was [laughs]. JOËL: On that theme of I wish that I could have something that behaved just a little bit more...like, I'm doing something slightly weird, and I wish they would behave more, like, just plain Ruby does normally with my, like, collections I'm familiar with. I'm going to pitch a talk that I gave at RubyConf Mini called "Teaching Ruby to Count." Some of these mental models actually showed up there. But the whole idea is like, oh, if you're bringing in sort of more custom objects and all of that, how can you just tweak them a little bit so that they're just as joyful to use and interact with as arrays, and numbers, and ranges? And they just sort of fit into that beauty of Ruby that we get out of the box. STEPHANIE: Awesome. On that note, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at: tbot.io/referral. Or you can email us at: referrals@thoughtbot.com with any questions.
Joël and Stephanie talk RailsConf! (https://railsconf.org/). Joël shares how he performed as a D&D character, Glittersense the gnome, to make his Turbo features talk entertaining and interactive. Stephanie's talk focused on addressing test pain by connecting it to code coupling, offering practical insights and solutions. They agree on the importance of continuous improvement as speakers and developers and trying new approaches in talks and code design, and recommend Jared Norman's RailsConf talk on design patterns, too! That One Thing: Reduce Coupling for More Scalable and Sustainable Software (https://www.informit.com/articles/article.aspx?p=2222816) Connascence.io (https://connascence.io/) [Connascence as a vocabulary to discuss coupling](https://thoughtbot.com/blog/connascence-as-a-vocabulary-to-discuss-coupling](https://thoughtbot.com/blog/connascence-as-a-vocabulary-to-discuss-coupling) The value of specialized vocabulary (https://bikeshed.thoughtbot.com/356?t=0) Transcript: We're excited to announce a new workshop series for helping you get that startup idea you have out of your head and into the world. It's called Vision to Value. Over a series of 90-minute working sessions, you'll work with a thoughtbot product strategist and a handful of other founders to start testing your idea in the market and make a plan for building an MVP. Join for all seven of the weekly sessions or pick and choose the ones that address your biggest challenge right now. Learn more and sign up at tbot.io/visionvalue. JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. STEPHANIE: And I'm Stephanie Minn. And together, we're here to share a bit of what we've learned along the way. JOËL: So, Stephanie, what's new in your world? STEPHANIE: So, I think I can speak for both of us and say what's new in our world is that you and I just came back from RailsConf in Detroit. JOËL: Yeah, we were there for, I guess, it's a three-day conference. Both of us were giving talks. STEPHANIE: Yeah. I don't think we've both spoken at a conference for at least a little over a year, so that was really fun kind of to catch up in person. And there was a whole crew of thoughtboters who were there. Yeah, I feel like we were hanging out, like, a lot [chuckles] all of last week, just seeing each other, talking about, you know, rehearsing our talks and spending time together on...there was, like, a hack day, and we were sitting at the table together. So, I feel like I'm totally caught up on everything that's new in your world, and that's it. That's the end of the show [laughs]. JOËL: On that note, shall we wrap up? STEPHANIE: [laughs] That would not be very fair to our listeners. [laughter] JOËL: Yeah. So, how was the conference speaking experience for you? STEPHANIE: Ooh, it was really great this year. I have not spoken at a RailsConf before, so this was actually, I think, a bigger stage than I had experienced before, and I had a great time. I met Ruby friends, new and old, and, yeah, I left feeling very gooeyed, and very energized, and just so grateful for the Rails community [laughs]. Yeah, I had a very lovely time, kind of being a little bit outside my normal life for a few days. And I think my favorite part about these things is just like, anywhere you go, you can kind of just have a shared interest with someone, and you can start a conversation with them. JOËL: That's really interesting. Do you find yourself just reaching out to strangers at conferences like this? Or do you tend to just hang out with the people that you know? STEPHANIE: Oh, I think a little bit of both. I like to get meals with people I know. But if I'm just hanging out in, like, the lobby or if I happen to get a seat for a talk and I'm sitting next to someone that I don't know, I find it quite easy to just be like, "Hi, like, I'm Stephanie. Are you excited for this talk?" Or, like, "What good talks have you seen recently?" There's an aspect of, like, the social butterfly that comes out of me when I'm at these things. Because I just don't get to have, like, easy access to, I don't know, people with, like, that shared interest or people who are willing to just have a conversation with you normally, I think. JOËL: Yeah, would you describe yourself more as an introvert or an extrovert? STEPHANIE: I am an extroverted introvert [laughter]. I feel like maybe that might be interpreted as a non-answer, but I think I lean more on the introvert side. But you know when you're with a group of people, and there's not, like, a very clear extrovert in that conversation, and then you're like, oh, I have to do the heavy [chuckles] lifting of the social lubrication [laughs] in this conversation, I can step into that role, reluctantly [laughs]. JOËL: Okay. I like the label that you used, the extrovert introvert, in that I enjoy social situations. I do well in social situations. But they also consume a lot of energy for me. I don't necessarily get sort of recharged by doing social events. So, people will be surprised when they find out that I tend to talk about myself as an introvert because, like, "Oh, but you're, like, you know, you're not awkward. You engage very well in different group situations." STEPHANIE: You have a podcast [laughs]. JOËL: And the truth is I enjoy those things, right? I really like social interaction, but it does, after a while, wear me out. STEPHANIE: Yeah, that makes sense. I did want to spend a little bit of time talking about the talk you gave at RailsConf this year: "Dungeons & Dragons & Rails." JOËL: I got to have a lot of fun with the theme. The actual content was introducing people to Turbo by building an interactive Dungeons & Dragons character sheet using vanilla Rails and a little bit of Turbo. So, we're not even writing any JavaScript. We're just using the Turbo helpers, a little bit of Action Cable to mimic something a little bit like...people who are in the know might be familiar with the site D&D Beyond, which is kind of the official D&D online character sheet website. Of course, it wasn't anywhere near as fancy because it's a 30-minute talk and showcasing different features, but that's what we were aiming for. STEPHANIE: Yeah, you know, you've talked a bit about giving talks on the show before, but I wanted to get into what made this one different because I think it could be fun for our listeners. [laughter] JOËL: The way I structured this talk so it has a theme. It's about Dungeons & Dragons, and we're building a character sheet. The way I wrote the talk was it's broken up into chapters. Each chapter is teaching a new feature in Turbo that I want to show off. In order to motivate learning each of these features...because I don't like to just say, "Oh, here's a thing that technology can do. Oh, here's a thing that technology can do." That's boring. You need a reason to learn that. So, I needed a reason to say, "We need to add this to a character sheet." So, every sort of chapter of the talk opens up with a little narrative portion. We're following this character, Glittersense, the gnome, and he's on adventures. And at different points in the adventures, he's going to do different types of roles or need different stats and things. And so, when we reach the point in the adventure where we need that, we sort of freeze frame and then say, "Okay, let's add that as a feature to the character sheet." And then, oh no, it turns out that this feature is a little bit more complicated. We're going to have to learn a new Turbo feature to do that. Who would have guessed? And then, we learn a new Turbo feature together. And then, we go back to the narrative portion. The adventures of Glittersense continue. And then, oh no, we're going to need to add another feature to the character sheet. And that's sort of how the talk is structured. STEPHANIE: Yeah. And you did a really cool thing with the narrative portions, which was you basically performed as Glittersense, the gnome, voice and posture, and a lot of really great acting from you [laughs], in my opinion. JOËL: That is something that came out pretty late in the talk preparation. So, I knew I wanted this kind of alternating story and code structure. Then, like, the weekend before RailsConf, I'm running through my slide deck, and I realized, you know what? What if instead of narrating Glittersense's adventures, what if I went first person for those sections? Glittersense tells his own story. And then, from there, it wasn't a big jump to say, you know what? This is D&D. If I'm going first person and narrating, I really should do a voice. And this is a conversation I had with a couple of people at the speaker dinner. And, of course, everyone's like, "You should 100% do the voice." And I was really not feeling confident in my ability to pull it off. So, for the next two nights, because I was speaking on the third day, the next two nights at the conference, in the evenings, I'm in the hotel room in front of the mirror just practicing my gnome voice to try to get something that got the persona of Glitterense, the gnome, across to the audience. STEPHANIE: How would you describe the persona? JOËL: Very extra. STEPHANIE: [laughs] JOËL: Very high energy. STEPHANIE: Yes. The name Glittersense is very extra, after all. JOËL: [laughs]. I punctuated a lot of the things that he says with just high-pitched laughter. He's also...so, the framing device for all of this is that you're in a tavern listening to him tell his adventures. I wanted a little bit of the sense that Glittersense is maybe embellishing a little bit. I think it may be too much to say he's full of himself, but he's definitely making himself to be the hero of the story, and maybe making himself to be slightly cooler than he really was. STEPHANIE: Yeah. I definitely got, like, a little bit of eccentricity, too, from the persona. And you know when you just, I don't know, meet an older person who has, like, a lot of life experience, and they want to tell you about it [laughter], but you do kind of maybe have a little bit of suspicion around how much they're exaggerating [laughs]. But it was really fun. Everyone I talked to afterwards, like, loved it. And I got to share the little nugget that, like, oh yeah, and Joël only, like, started doing the voice, like, decided that he was going to do it two days ago. And they were just all really, like, blown away because it seemed so well practiced, and it was really fun. JOËL: I got to do something really fun, also, with physical space because Glittersense narrates his portion, sort of the story portions, but then the code portions where we're talking about Turbo, I'm talking in my own voice. And so, when I'm talking about Turbo, I'm standing at the lectern. And when I'm Glittersense, I'm kind of off to the side on the stage and doing the voice. And so, there's this almost, like, two worlds that are inhabited: one by Joël, the speaker, and one by Glittersense, the gnome. And it got to the point where I don't say or do anything. I only move from the lectern to the, like, portion of the stage where Glittersense lives. And the audience starts chuckling and, like, nothing has happened yet, like, no jokes have been told. No voice has happened. No slides have changed. But the anticipation, people know what's coming. STEPHANIE: Yeah. And I think the best part, what I really found just really fun and, I don't know, every time it happened, I just really enjoyed it, when you transitioned out of Glittersense, the gnome, and back to Joël because you were so nonchalant about it. You kind of, like, straighten up rather than having your little kind of crouchy gnome posture, and then just walk across back to the podium. And then, in your normal voice, go back to just, you know, sharing very...not necessarily dry, but just, like, straight to the point. "And this is, like, how you, you know, create a frame in [laughs] Turbo," as if nothing happened [laughs] when even just, like, you know, 20 seconds ago, you were just enthusing about, like, slaying the bandit, chieftain [laughter] known as Glittersense. JOËL: Uh-huh. I think, especially when I open, so I get introduced. I'm off stage. I walk onto the stage, and I'm immediately Glittersense. And I'm telling a story, and the intro goes on for, like, quite a while. It's a big story chunk. And then, at some point, I just walk over to the lectern, drop the voice, hit next slide, and it's my title slide. I'm just like, "Okay, now welcome to Dungeons & Dragons on Rails. We're going to build a character sheet together." STEPHANIE: Yeah, that's exactly the moment I'm thinking of. JOËL: The walking in as Glittersense and just immediately going to the voice caught everyone by surprise. And then, the, like, oh, he keeps going for this. Is the whole talk going to be like this? And then, the, like, just when you think, oh, he's really going for it, the, like, dropping it and going to the podium and title slide. It wasn't intended to be a funny moment, but I think the contrast and the fact that I just switched over was one of the biggest laughs I got. STEPHANIE: Yeah, I mean, I think that attests to how good the delivery of it was because that contrast was very felt. So, props to you. JOËL: I love the idea of, you know, the thought that you put into building a talk and, like, the narrative structure and the pedagogy of the stuff. And, I think, in this particular case, this is almost like a narrative approach called in media res, where you start kind of in the middle. You open your book, or your movie, or whatever in the middle of the story. And then, you kind of come back to the beginning at some point later. So, it starts with some kind of action scene that grabs your attention. So, in this case, my title slide is 10, 15 slides into the talk. We get immediately started with Glittersense and his adventures. And then, once we're sort of all bought into this world, then we move to the title slide and talk about, okay, we're here to build a character sheet and all that stuff. And I think that it wouldn't have had the same impact if I'd, like, opened with that and then gone into Glittersense's adventures. And that's something that was not the case at the beginning. I really reworked the talk to make it in that order. And I think that the talk had a lot more impact for doing that. STEPHANIE: Yeah, definitely. I guess I also just wanted to point out that this is very different from all your other talks. And I think it's really cool that, you know, you are a veteran speaker, but you still find ways to do something new and try something that you've never done before, and yeah, find ways, new ways to, like, speak and engage people and teach. I don't know, do you have just any thoughts about why or how you got into a position to be like, "Oh, you know, I'm going to do something super different this time around" [laughs]? JOËL: So, every talk I give, I try to do something new, something different, to push myself as a speaker to get better. That might be in the writing of the talk; that might be in the delivery. More recently, I've been trying to do more with dynamic presence on stage. So, when I spoke at RubyConf San Diego, I was trying to not just stand at the lectern but to learn to be able to give my talk while also, you know, walking around the stage, looking at the audience, making pauses where it's necessary, not to just be so into the delivery of the talk by just standing at the podium and, like, going through my deck, which is a small thing but I think is an area I wanted to improve in. This time, I was playing around with some more narrative framing and ended up, yeah, like, pushing it to an extreme. And it works with the theme because inhabiting a character and role-playing is the core part of D&D. Not everybody plays a D&D character by doing a voice. You are a little bit extra if you do that. But it's not uncommon for people to do a voice. And so, it kind of fit perfectly with my theme. I just needed to get the self-confidence to do it. So, thank you to everyone at the speaker dinner that was like, "No, you totally got this. You should do this," because I was feeling very unsure. STEPHANIE: It really paid off, so... JOËL: I'd like to circle back to your talk, though. So, you gave, basically, the first talk of the conference. You were the first session after the keynote. A theme that came up multiple times in your talk was this idea of coupling and how it affects different parts of our code and, particularly the way that we structure tests or the way that we feel test pain. How did you, when you were prepping this talk, discover that theme and decide to lift it up? Was that something that you knew ahead of time you wanted to talk about, or did it just sort of emerge as part of the talk preparation process? STEPHANIE: That's a really great question, and I'm glad you picked up on that. So, my talk was called: "So, Writing Tests Feels Painful. What Now?" Originally, when I came up with this idea, it actually started with coupling. I realized that I wanted to give a talk about coupling because it's just something that I was struggling with or, like, had seen other people struggle with and really wanting kind of a discrete resource, wanting to provide that. But as I was just thinking about it, I was like, oh, like, there are so many different ways that this could go. On one hand, it was a very like important topic to me, but also maybe too big of a topic. And so, I actually, like, kind of put that on the back burner. And it wasn't until later when I connected it to another...it wasn't necessarily different at all, but just, like, an extension of this idea is, oh, like, people are struggling with coupling in tests or, like, it manifests in tests. And so, I thought maybe that could be the angle that I took on this topic that kind of gave me a little bit more focus. And I didn't even end up saying like, "Yeah, this talk was, like, born out of just, you know, wrestling with coupling or anything like that." So, it's cool, to me, that you picked up on it as a theme because it was...I had, you know, ended up not being super explicit about it, but it was certainly, like, a thing that was driving the content from my perspective. JOËL: Interesting. So, it started as a coupling talk and then got sort of focused through the lens of testing. STEPHANIE: Yeah. And I think there was a part of me that was like, you know, I don't know if I could just teach the concept of coupling, like, by itself without the framing of testing for people who this is, like, a new concept for them. I realized that maybe it would be more effective to be like, "Hey, like, have you experienced test pain? You know, have you had to mock out a billion objects or changed, you know, made one change and then had to fix, like, a million tests subsequently? Then this talk is for you." And then weave in the idea of coupling in it to kind of start to help people feel familiar with it or just, like, identify it without as much, like, jargon as kind of I've seen when I've tried to figure out, like, how to manage it. JOËL: It's interesting because I think it gives you a, like, concrete, valuable thing to optimize for as opposed to, like, hey, let's lower coupling because then you're writing, you know, quote, unquote, "better code." And you get to feel better about yourself as a programmer because you're doing things the, quote, unquote, "right way." That's very kind of hand-wavy, and I think sometimes leads people down a bad path where they're optimizing things that they shouldn't be. But the tests give you this very concrete way to say, "Hey, we're not just trying to reach the, like, low score record for the app in terms of coupling. We're trying to reduce test pain. Tests are painful. And that pain is telling us something. It's telling us that we've crossed some sort of threshold for coupling. Let's find ways to reduce it, not so that we can feel good about ourselves, but so that our tests are actually manageable." STEPHANIE: Yeah, I am really glad you picked up on that, too, because I feel the exact same way when someone just tells me to decouple something or, like, makes a note that, like, oh, this feels really coupled. I don't know what that means necessarily. And it's not very convincing to just be like, "Oh, you should write loosely coupled code [laughs]," at least for me. What you said just now, it's like, it's not to feel good about ourselves, you know, to write code that way, but, actually, to just feel good about our code, period [laughs]. And, yeah, finding that validation through just, like, actually working with code that is easier to change that is the goal, not necessarily to, yeah, kind of pursue some totally subjective, like, metric. JOËL: So, one of the kinds of coupling that you called out, I think, was where you hardcode a class name of some other class in your object. And that feels, like, really sort of innocuous. Like, of course, my objects can talk to other objects. And maybe I want to, like, refer to a class somewhere. Why is that such a like tricky piece of coupling to work with? STEPHANIE: It's not necessarily intentional sometimes. Like, you just do it because you're like, well, I need access to this class somewhere, and I happen to already be in this file. So, why not just hard-code it here? I do think it's a little tricky because the file that you're writing might be, like, very far down in, like, your code flow or, like, your code path, like, very far from, like, a controller or any kind of entry point into your system, at least based on what I've seen in a lot of modern Rails apps. And so, I think that coupling gets really, really obscured. I have found that, like, if I have to kind of write a more, like, a higher level test, like, maybe a request spec or something, there are times when I'm, like, having to deal with a lot of classes just to set stuff up in a test like that that I didn't think I would have to [chuckles] when I first went about trying to just be like, oh, like, let's just figure out how to get a 200 response [laughs] from this request. So, you're really burying perhaps the things that are needed to set up, like, that full path of execution. And sometimes, it only comes out when you're writing a test for it. JOËL: And you mentioned briefly, in passing, the idea that oftentimes this sort of coupling manifests as a lot of extra test setup because your object that you're trying to test now also needs all these other things that are related in order to be tested. But sometimes even when you hard code a class, though, you can't even just say, "Oh, I want this particular user or something returned." So, you have to then do something like allow this class to receive class method and return, and now you're stubbing. And I don't know how you feel about stubs in RSpec. I always treat them a little bit like a code smell in the like classic sense of it's not necessarily bad, but maybe pause, take a look, and ask yourself, "Why is that there, and should I do things differently?" STEPHANIE: Yeah. I ended up having, like, a lot of examples of stubbing in my example because the code had just been set up where that was the only way that you could access those collaborators, essentially, to, like, make an assertion on them, or have them do something different because you actually needed to go into a different path, right? And I was like, yeah, this should feel weird. You should feel a little bad [laughs] or at least, you know, kind of just pay attention to that feeling, even if you can't really do anything about it in that particular instance. But on the flip side, you know, it's like, yes, it feels a bit strange, you know, but it's not all bad, right? Like, you're kind of learning like, oh, hey, like, I am coupled to this hard-coded class because I am needing to stub, like, a class method that returns it, or that constructs it. And at least you've exposed that, you know, for yourself. One thing that I was running into a lot in my example, too, was that those things, like, weren't obvious when you were just reading maybe, like, the public methods and trying to figure out what was happening in them because they were wrapped in private methods. I was a little bit conflicted about this because there were times when it was already just a single method call, but then it was just kind of wrapped in a private method that actually hid [laughs] the things, like all the dependencies that were passed as arguments. And I found that to be, sure, it looks kind of cleaner. But then all you need to do is scroll down [laughs], and then you're like, oh, actually, there's all these other things involved, but it was kind of hidden away for me. And I found that, actually, like, at least when I actually needed to change things, less helpful than I imagine what the, you know, code author intended. Do you have any thoughts about hiding details like that? JOËL: I'm kind of a big fan. STEPHANIE: Hmmm. JOËL: The general idea, I think, is called the single level of abstraction principle. Whatever sort of public method that you're calling is often implemented in terms of...let's say it does a few different things. It's implemented in terms of, like, these sort of high-level concepts. So, whoever is reading the public method doesn't need to like care about the details of how each step is implemented. So, maybe you're fetching something from an API, and then you're making a database call, and then you're doing some transformation and creating some new objects from it. Having all of the, like, HTTP calls and the ActiveRecord stuff and the, like, transformation all in the public method, yes, there's a lot of complexity happening there, and it makes that obvious. But it also makes it really hard to get a sense of what is happening. So, I like to say, "Hey, there are four steps. Let's wrap them all each in a private method then you can call all of those in the public method." The public method now sort of reads like a very simple sort of script. First, fetch data from the HTTP API, then fetch some data from the database, then apply this transformation, then create this object. And if I'm mostly caring about what this object does and not the how let's say I'm building some other objects that interact with this, that is the information I want to know. Where I care about the actual implementation of, oh, well, exactly how is the ActiveRecord stuff done when I'm doing internal changes to the object, that's when I care about those private methods. I think where it gets tricky, and I think that's the point that you were bringing up, is that if you write code in that way, it has to change the heuristics of how you read code to detect complexity. Because, oftentimes, I think a very classic heuristic for code complexity is just line length. If you have a 50-line method, probably there's a lot of complexity there. Maybe there's a lot of coupling. If it's a four-line method that is written at a high level of abstraction that just calls out to private methods, you scan over. You're like, oh, nice and clean. Nothing to see here. Move on. And so, that heuristic doesn't really hold up in a codebase where you're applying this single level of abstraction. Do you think that lines up with your experience? STEPHANIE: Hmm. As I was listening to you, I was like, yeah, like, that makes total sense to me. But then I also clearly disagreed a little bit [laughs] in my initial...kind of what I was saying initially. And I think it's because that single layer of abstraction was not very well defined. JOËL: Hmm. That's fair. STEPHANIE: Yeah. Where, in fact, it was actually misleading. Like, it wanted to be at that level of abstraction, but it really wasn't. Like, it was operating on things at, like, a lower level and wasn't designed with that kind of readability in mind. So, it was more, like, it was just hiding stuff a little bit, at least for me. And, I think, it certainly would have taken, like, more work to figure out what that code, like, really was meant to convey. It might have taken some refactoring to coalesce at that single level. And that was essentially kind of what I was showing in my talk as, like, how to get to saying, like, "Hey, we actually are operating in the lower level, but I don't think we need to." There was some amount of, like, looking at all of the how to figure out, like, oh, maybe these things we don't even need to expose in this class. And we kind of got to a place where those details weren't, like, needed in that class at all. So, it's one of those things where it's harder than it sounds [laughs]. JOËL: It's definitely an art. STEPHANIE: Yeah. JOËL: And I think what you're saying about some of the coupling being, like, scattered throughout the class, it's something that I see a lot with situations where you're coupled, not so much to, like, a single class, but to something side effectful. So, you're building some kind of integration with a third-party API, and you're going to have to make a lot of HTTP calls. And each of those might be individually simple, and they're all sort of maybe in different private methods or whatever, or they're interspersed among a larger chunk of logic. And that makes your tests really complicated. But there's no, like, one place you can point at and be like, ooh, that's the one place where there's a lot of complexity. What's happening here, though, is that your business object that's doing stuff is coupled to the network, and that coupling is going to force you to do some stubbing. It's going to force you to deal with a bunch of side effects that are non-deterministic in your code. And you used the word coalesce earlier that I really liked because I think that's often a situation where you do have to stand back and say, "Look, there's a lot of HTTP going on here. What if I coalesced it all into an object? Now I have two objects: one that's responsible for business logic, and one that's responsible for just the HTTP calls." And, all of a sudden, the tests just totally simplify. And we've removed some coupling, but that's not something that you would have seen just from reading the code. Because, as you were saying, it's sort of scattered in little bits and pieces throughout your file that don't necessarily catch your eye. STEPHANIE: Yeah. Which brings me to a blog post that I had found a lot of inspiration from in the talk that I'll link. It's called "That One Thing: Reduce Coupling for More Scalable and Sustainable Software." But it's actually about tests [laughs], even though it doesn't make an appearance in the title of the blog post at all. But this is where I kind of got the idea of necessary versus unnecessary coupling in test. Because I had never thought about how, yeah, like, when you write a test, you are very correctly coupling yourself to at least the method and class under test [laughs], if not also the arguments, right? Or anything else needed to construct what you're testing. And literally having that listed out for me in this blog post I think it's a...they use some examples in Java. And so, there's, like, a little bit more [laughs] setup involved. But I think they're like, yeah, these are six things that, like, it's mostly fine if you're coupled to these because that's kind of what needs to happen in a test. But, like, even having something to compare a test I wrote to just, like, okay, these are the things I know I need. And then, you can start to see when you've diverged from that list, when you are finding yourself coupled to some internals of your class. I really...that was actually, like, really helpful for me because, as we talked about earlier, like, it can be kind of communicated so abstractly. But here is, like, a very clear heuristic for when you should at least, like, start to pay attention or be like, oh, this is something that was needed to get the test to run but is now starting to feel a little unnecessary because it's not on this list. JOËL: That list reminds me, or the idea of a list of things to check out for when thinking about coupling, reminds me of the concept of connascence, which is a fancy word for almost a, like, categorization of different types of coupling because coupling comes in different flavors, some of which are tighter forms of coupling than others. And so, having that vocabulary has been really helpful for me when I'm looking at PRs and code review, or even when I'm refactoring my own code. Kind of like that list that you mentioned that you have, now I have some heuristics to look at that and say, "Oh, can I go from a connascence of position to a connascence of naming, and does that help me?" STEPHANIE: Yeah, I like that you mentioned the positional connascence because I also came across a really great metaphor for kind of things that need to change together, like, when that makes sense. And it was basically the idea of a dishwasher and a laundry machine [laughs]. I wish I could recall, like, what book this was from. But it was basically like, oh yeah, like, in theory, you're washing two things. So, maybe they are similar, but then you're like, no, actually, you want these to be a little bit separate because, you know, you don't want to wash your dishes and your clothes in the same machine. I don't know, maybe that exists [laughs], but I don't think it would do a very good job for either goal. And I think that was really helpful, for me, in imagining, like, the difference between kind of coupling and cohesion, like things that...even just imagining, like, kind of where I'm doing those things in the house, right? It's like, okay, that lives in a separate room. And, like, the kitchen is for the dishes, and that could be like, you know, a module if you will. And, like, laundry happens in the laundry room, and how to kind of just separate those things, even though they also do share some qualities, too. Like, they're both appliances, right? And so, that's the way that they are similar, but they're not the same. JOËL: You just mentioned the sort of keyword cohesion. And for our listeners who are not familiar with that term, it refers to an object sort of having one thing that it does well. Like, everything in that class sort of works towards the same goal, kind of similar to the idea of the single responsibility principle. So, in my earlier example, where we're sort of interspersing some business logic, a lot of HTTP requests, and pulling out an object that's focused on HTTP, like everything is based around that, now that object has higher cohesion because it's all doing one thing. So, if you read classic object-oriented literature, the recommendations that you'll typically see are that objects should have high cohesion and low coupling. STEPHANIE: Yeah. Think of a dishwasher and a washing machine next time [laughs] you come across something like that. Because I feel like those are really great, like, real-life examples of that separation. JOËL: Did you go to Jared Norman's talk on the third day: "Undervalued: The Most Useful Design Pattern"? STEPHANIE: No, I didn't. Can you tell me about it? JOËL: It felt like he was addressing a lot of the same themes as you were but from more of a code perspective than a test perspective. Talking a lot about, again, forms of coupling, dependencies, and then, specifically, one of the tools that he focused on to reduce the coupling that we see is value objects and factory methods to construct those. So, for any of our listeners who, when the talks come out, watch Stephanie's talk and are like, "Wow, I would love to learn more about this," a great follow-up, Jared Norman's talk: "Undervalued: The Most Useful Design Pattern." STEPHANIE: Yeah, that's neat because I can see that being a solution to the hard code did class names that we were talking about earlier. And I like how that is kind of, like, a progressive lesson in coupling a little bit. I'm really glad you shared that talk with me because now I'm excited to watch it when it comes out. And in general, I just love learning new vocabulary or finding new ways to speak about this topic with clarity. So, if any of our listeners have just additional mental models for coupling [laughs] different metaphors, different household appliances [laughs], or something like that, I would love to know. JOËL: You would like that, given that our first episode together was about "The Value Of Specialized Vocabulary." STEPHANIE: Yeah, it's clearly undervalued. JOËL: Haha, I see what you did there. STEPHANIE: Thank you. Thank you very much [laughs]. JOËL: On that terrible/wonderful pun, shall we wrap up? STEPHANIE: Let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at: tbot.io/referral. Or you can email us at: referrals@thoughtbot.com with any questions.
Joël shares his preparations for his RailsConf talk, which is D&D-themed and centered around a gnome character named Glittersense. Stephanie expresses her delight in creating pod-related puns within thoughtbot's internal team structure, like "cross-podination" for inter-pod meetings and the adorable observation that her pod resembles "three peas in a pod" when using the git co-authored-by feature. Together, Stephanie and Joël discuss bringing one's authentic self to work, balancing personal disclosure with professional boundaries, and fostering psychological safety. They highlight the value of shared interests and personal anecdotes in enhancing team cohesion, especially remotely, and stress the importance of an inclusive culture that respects individual preferences and boundaries. Transcript: We're excited to announce a new workshop series for helping you get that startup idea you have out of your head and into the world. It's called Vision to Value. Over a series of 90-minute working sessions, you'll work with a thoughtbot product strategist and a handful of other founders to start testing your idea in the market and make a plan for building an MVP. Join for all seven of the weekly sessions, or pick and choose the ones that address your biggest challenge right now. Learn more and sign up at tbot.io/visionvalue. STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: So, at the time of this recording, we're recording this the week before RailsConf. I've been working on some of the visuals for my RailsConf talk and leaning on AI to generate some of these. So, my talk is D&D-themed, and it's very narrative-based. We follow the adventures of this gnome named Glittersense throughout the talk as we learn about how to use Turbo to build a D&D character sheet. And so, I wanted the AI to generate images for me. And the problem I've had with a lot of AI-generated images is that you're like, okay, I need a gnome, you know, in a fight doing this, doing that. But then, like, every time, you get, like, totally different images. You're like, "Oh, I need an image where it's this," but then, like, the character is different in all the scenes, and there's no consistency. So, I've been leaning a little bit more into the memory aspect of ChatGPT, where you can sort of tell it, "Look, these are the things. Now, whenever I refer to Glittersense, whenever you draw an image, do it with these characteristics that we've established what the character looks like." Sometimes I'll have, like, a text conversation kind of, like, setting up the physical characteristics. And then, it's like, okay, now every time you draw him, draw him like this, or now every time you draw him, draw him with this particular piece of equipment that we've created. And so, leaning into that memory has allowed me to create a series of images that feel a little bit more consistent in a way that's been really interesting. STEPHANIE: Cool. Yeah, that makes sense because you are telling a story, right? And you need it to have a through line and the imagery be matching as you progress in your presentation. I actually don't know a lot about how that memory works. Does it persist across sessions? Do you have to do it all in one [laughs] go, or how does that work? JOËL: So, there's, like, a persistent chat. So, you can start sort of multiple conversations, but each conversation is its own thread with its own memory. And it will sort of keep track of certain things. And sometimes I'll even say, "Hey..." instead of, like, prompting it for something to get a response, you could prompt it to add things to its memory. So say like, "From now on, when I ask you these types of questions, I want you to respond in this way," or, "From now on, when I ask you to generate an image, I want it done in this format." So, for example, RailsConf requires all of their slides to be 16 by 9. If I want, like, a kind of cover image or, like, something full-screen, I need an image that is 16 by 9. So, one of the things I prompt the AI with is just, "From now on, whenever you generate an image, give me an image in 16:9 aspect ratio." STEPHANIE: Cool. I also was intrigued by your gnome's name, Glittersense. And I was wondering what the story behind that character is. JOËL: The story behind the name is that I was playing D&D with a friend who was this very kind of eclectic Dragonborn character. And I did some sort of valiant deed and got the name Glittersense bestowed upon me by this Dragonborn for having helped him out in some, like, cool way. So, that's a fun name. And so, when I was searching for a name for my character in this talk, I was like, you know what? Let's bring back Glittersense. I like that. I think it captures a little bit of, like, the wonder and the whimsy of a gnome. STEPHANIE: That's really cute. I like that a lot. JOËL: So, Stephanie, what's been new in your world? STEPHANIE: So, lately, I've been having a lot of fun with coming up with names of things. You know the saying how naming is one of the hardest things in software? Well, okay, I'm not actually going to talk about anything that I named very particularly well in my code, but I've been just coming up with a lot of puns. It's just, I don't know, my brain is kind of in that space. And one thing that...I can't recall if I have talked about this on the show before, but our team at thoughtbot is experimenting with kind of smaller sub-teams within it called pods. We have now kind of been split into pods with other people who are working on maybe similar client projects. I have been having some really good naming ideas around [laughs] pod-related puns. So, one thing that we did as part of this experiment was setting up meetings for pods to meet each other, and spend time together, and kind of share what each other was up to. And I was the first to coin the term cross-podination, kind of like cross-pollination. And I think I just, like, said it offhand one day, and then it caught on. And I was very pleasantly surprised to see that people just leaned into it and started naming those meetings cross-podination meetings. And then, another one that came about recently was my pod there's three of us in it, and we were pairing, or I guess it's not really called a pairing if there's three. We were mobbing or ensembling, whatever you want to call it. And sometimes we like to use the git co-authored-by feature where you can attribute, you know, commits to people that you worked on them with. And in GitHub when you, you know, add people's emails to the commit, you know, you see your little GitHub profile picture in a little circle. And when you have multiple people shared on a commit, it is just, like, squished together. And since we're a trio, I was like, "Oh, it's like we're, like, three peas in a pod." JOËL: [chuckles] STEPHANIE: And I realized that it was an excellent missed opportunity for our pod name. We're something else. But I am hereby reserving that name for the next pod that I am in. You heard it here first [laughs]. It looked exactly like just three snug little peas. And I, yeah, it was very cute. I was very delighted. And yeah, that's what's new for me. JOËL: I'll also point out the fact that you are currently talking on a podcast. STEPHANIE: Whoa, whoa. So, you and I are a pod [laughter]. We're a podcasting pod [laughs]. Wow, I didn't even think about that. My world is just pods right now [laughs], folks. JOËL: How do you feel about puns as an art form? STEPHANIE: [laughs] Wow, art form is a strong phrase to use. I don't hate them. I think it depends. Sometimes I will cringe, and other times I'm like, that's great. That's excellent. Yeah, I think it depends. But I guess, clearly, I'm in my pun era, so I've just accepted it. JOËL: Are you the kind of person who is, like, ashamed but secretly proud when you make a really good pun? STEPHANIE: Yeah, that's a very good way to describe it. I'm sure there are other people out there [laughs]. JOËL: What's interesting with puns, right? Like, some people love them, some people hate them. Some people really lean into them, like, that becomes almost, like, part of their personality. We had a former teammate who his...we made a custom Slack emoji with his face, and it was the pun emoji because he always had a good pun ready for any situation. And so, that's sort of a way that I feel like sometimes you get to bring an aspect of your personality or at least a persona to work. What parts of yourself do you like to bring to work? What parts do you like to maybe leave out? STEPHANIE: Yeah, I am really excited about this topic because I feel like it's a little bit evergreen, maybe was kind of a trendy thing to talk about in terms of team culture in the past couple of years, but this idea of bringing an authentic or whole self to work as, like, an ideal. And I don't know that I totally agree with that [laughs] because, like you said, sometimes you have a different kind of persona, or you have a kind of way that you want to present yourself at work. And that doesn't necessarily mean it's a bad thing. I personally like some kind of separation in terms of my work self and my rest of life self [laughs]. Yeah, I just think that should be fine. JOËL: So, you might secretly be the pun master, but you don't want your colleagues to know. STEPHANIE: [laughs] That's true. Or I save my puns only for work [laughter]. If I ever have, like, a shower thought where I think of a really good pun, I will, like, send a Slack message to myself to find [laughs] the perfect opportunity to use this pun in a meeting [laughs]. I don't actually do that, but that would be very funny. JOËL: I feel like there's probably a sense in which nobody is a hundred percent their authentic self or their full self in a work situation, you know, it varies by person. But I'm sure everybody, to a certain extent, has a professional persona that they inhabit during work hours. STEPHANIE: Yeah, and I like that the way we're talking about it, too, is a professional persona doesn't necessarily mean that you're just a little...matching kind of a business speak bot [laughs], where it's kind of devoid of personality, but just using all the right language in their emails [laughs] and the correct business jargon or whatever. To me, what is important is that people are able to choose how they show up or present themselves at work. That's, like, an active choice that they're making, not out of obligation or fear of consequences. You know, like, it's fine to be a little more private at work if that's just how you want to operate. And it's also fine to be more open about sharing things going on in your personal life. Because I've seen ways in which both have been more enforced or, like, there's pressure to perform one way or another. And that could mean, like, when people kind of encourage others to try to be more of themselves or, like, share more things about personal life. That's not always necessarily a good thing if it's not something that people are comfortable with. And I suspect that we have kind of pulled back a little bit from that, but there was certainly a time when that was a bit of an expectation. And I'm not sure that that was quite [chuckles] what we wanted to aim for in terms of just the modern workplace. JOËL: It is interesting because I think there can be some advantages to maybe building connection with people by sharing a little bit more about your life. But, again, if there's pressure to do it, that becomes really unwholesome. STEPHANIE: Yeah. Unwholesome is a good word to use. Like, I want that wholesome content [laughs] at work. And I actually have a couple of thoughts about how I prefer to share, like, just personal things with my team members. And I'm curious kind of where you fall on this as well. But a couple of things that our team does that I really like is we have a quarterly newsletter that one of our team leads puts together. She has an open call for submissions, and people just share any, like travel plans, any professional wins, any kind of personal life things that they want to share. People love talking about their home improvement adventures [laughs] on our team, which is really fun. And yeah, like, just share photos and a little blurb about what they've been up to. And this happens every quarter. And it's always such a delight to remember a little bit like, oh yeah, my co-workers have lives outside of work. But I really like that it's opt-in and also not that frequent, you know? It's kind of like, this is the time to share any like, special things that have happened in the past three months. And yeah, I think every time a new dispatch of it comes out, everyone kind of gets the warm and fuzzy feelings of appreciating their co-workers and what they've been up to. JOËL: Do you think that that kind of sharing sort of maybe helps personalize a little bit of our colleagues, especially because we're all remote and we're interacting with each other through a screen? STEPHANIE: Yes. Yeah. That's another good distinction. I think it is, like, a little more important that there are touch points like these when we are working remote because, yeah, the water cooler conversation just doesn't really happen nearly as much as it does when you're in an office. And I feel like that's the kind of thing that I would talk about at the water cooler [laughs]. It's like, "Oh yeah, I went to Disney World, or traveled for this conference, or I built new garden beds for my yard," just stuff like that. I don't know, I don't find that...like, when you're just communicating over Slack and email, there's not a good place for that kind of stuff. And that's why I really like the newsletter. JOËL: One thing that's interesting about the difference between in-person and remote is that, in person, a way that you can express personality in the office is you can do some things with your workspace. You might have some items on your desk that are of personal interest. And, you know, you might still do that when you're working remote, but those don't get captured by your webcam unless it's in your background. Your background you can get real creative with. But you can also, like, really curate that to, like, show practically nothing. Whereas if you were putting things on your desk in the office, there's kind of no way for your colleagues not to see that. So, you had to be...like, it had to be things that you were willing for everyone to see. But at the same time, sometimes it's nice to be able to say, hey, I'm going to put a touch of, like, things that are meaningful to me in my work life. STEPHANIE: Yeah, I really like that. I mean, Joël, your background is always these framed maps on the wall, hanging on the wall, and that is very you, I think. Did you kind of think about how they'll just be your background whenever you're in a meeting, or they just happened to be there? JOËL: So, these I had set up pre-pandemic. I like the décor. And then, when I started working from home in 2020, I was trying to figure out, like, where do I want to be to take meetings? And I was like, you know what? The math wall is pretty cool. I think that's going to be my background. I guess now it's almost become, like, a bit of a trademark. STEPHANIE: Yeah, I feel that. My trademark...I have a few because I like to move around when I take meetings. So, when I'm at my desk, it's the plants in my office. When I'm in my kitchen, it's either my jars [laughs]. So, I have, like, open shelving and just all of these jars of, you know, some of it is ingredients like nuts, and grains, and stuff like that, and some of it is just empty jars that I use for drinking water. So, I have my jar collection. And then, occasionally, if I'm sitting on the other side of the table [chuckles], all of my pots and pans are hanging in the background from above my stove. So, yeah, I'm the jars, pots, and plants person [laughs] at the company. JOËL: You know, we were talking earlier about the idea that it's harder to see your sort of workspace in a remote world. And I just remembered that we do a semi-regular...there's, like, a thread at thoughtbot where people just share pictures of their workspace, and it's opt-in. You don't have to put anything in there. But you get a little bit of, like, oh, the other side of the camera. That's pretty cool. STEPHANIE: Yeah, I love seeing those threads. And I think a lot of people in our industry are also gear nerds, so [laughter] they love to see people's, like, fancy monitor and keyboard setups, maybe some cool lighting, oh, like, wire organization [laughs]. JOËL: Cable management. STEPHANIE: Yep. Yep. Those are fun. And I actually think another one that we've lost since going remote is laptop stickers because that was such a great way for people to show some personality and things that they love, like programming stuff, maybe, like, you know, language stickers or organizations like thoughtbot stickers, too, and also, more personal stuff if they want. At a previous company, we were also remote, and someone came up with a really fun game where people anonymously submitted pictures of their laptop stickers. And we got together and tried to guess whose laptop belonged to who just based on the stickers. JOËL: Oh, that's fun. STEPHANIE: Yeah, that was really fun. I keep forgetting that I wanted to organize something like that for thoughtbot. But now I'm just thinking about it, and I feel the need to decorate my laptop with some stickers after this [laughs]. JOËL: One thing I do want to highlight, though, is the fact that several years back, when people were talking a lot about the importance of bringing your sort of authentic or whole self to work, one of the really valuable parts of that conversation was giving people the ability to do that, not forcing people to sort of hide parts of themselves, especially if they don't fit into a dominant culture or demographic, in order to be able to even function at work, right? That's a sort of key aspect of, I guess, basic inclusivity. And so, I think that's still a hundred percent true today. We want to build cultures that are inclusive, both in our in-person professional situations and for remote teams. STEPHANIE: Yeah, 100%. I think, for me, what I think is a good measure of that is, you know, how comfortable are people disagreeing at the company kind of in public or sharing an alternative perspective? Like, that should be okay and celebrated, even, and considered, you know, with equal weight as kind of what you're saying, the dominant identity or even just opinion. Like, especially in tech, I think people have very strongly held opinions, and when they're disagreed with...I've become a little skeptical of the idea of, like, this is how we do things here or, like, we don't do that. And I think that rather than sticking to a, like, stance like that, there's always room to incorporate, like, new approaches, new perspectives, new ways of thinking to a given problem. And that can only happen when people are comfortable with going there, you know, and kind of saying, like, "This is important to me," or, like, "This is how I feel about it." And that, in and of itself, is just equally valid [laughs] as whatever is taking the airtime currently. JOËL: That's really interesting because I feel like now you've leaned into almost the idea of psychological safety for a team. And if you're having to sort of repress or hide elements of the way you think, or maybe even sort of core elements of your identity to fit in with a team, that's not psychologically safe, and you can't have those deeper conversations. STEPHANIE: Yeah, 100%. I think it's two sides of the same coin, you know, it's like two ways of saying the same thing, that people should be able to conduct themselves in the way they choose to [laughs]. And I can't imagine anyone really disagreeing with a statement like that. JOËL: So, I know you choose to not always share everything about your life or sort of...I don't want to say bring your authentic self but, like, bring everything about yourself to the workplace. Do you have a sort of a heuristic for what you decide to share or not share? STEPHANIE: Yeah. I don't know if it's necessarily a heuristic so much as it's just what I do [laughs]. But I tend to do better with, like, smaller groups, and, actually, that's why I think pods has been working really well for me personally because I can share personal information just in a more intimate setting, which is helpful for me. And yeah, I tend to, like, find once, like, either Slack channels or Spaces, meetings are starting to get into the, like, 10, 11, 12 people territory is when I hold it back a little bit more, not because of any sort of, like, reason that I don't want to share. It's just, like, that's just not the venue for me. But I do love when other people are, like, open, even in, like, larger spaces like that. I appreciate when other people do it just to, you know, signal that it's okay [laughs]. And I enjoy throwing a reaction or responding in a thread about, you know, something that someone shared in a bigger channel. And I think that diversity is actually really helpful because it conveys that, like, there's different ways of existing online in your work environment and that they're all acceptable. What about you? How do you kind of choose where to share things about your personal life? JOËL: I think, kind of like you, I don't really have a heuristic. I just sort of go with gut feeling. I think I, sort of by nature, have always been maybe a little bit of having, like, separate professional and personal lives and keeping those a little bit more distinct. And, you know, there's some things that kind of cross over, like, oh, you know, I tried out this fun, new restaurant, or I did a cool activity over the weekend, or something like that. I think I've come to see that there can be a lot of value in sharing parts of yourself with other colleagues. And so, from time to time, I'll, like, maybe bring in something a little bit deeper. And, like you said, sometimes that's more easily done in a smaller context. And then yeah, for some things, it's like, okay, I'm going to share photos from a vacation in that, you know, quarterly newsletter. That's kind of fun. But also knowing that there's no pressure that's nice. STEPHANIE: Yeah. I think you're really good about finding the right avenues for that. I like, love when you show photos in the travel channel, even though I have that channel muted [laughs]. You'll, like, send me the link to the post in that channel. And yeah, I love that because it's a way for you to kind of, like, find the right place for it, and then also share it with any particular people if you choose to. JOËL: I think, also, personal connections can be a way to build deeper relationships, especially in smaller groups. And you can form deeper connections with colleagues over a particular project, or a particular technology, or a tech topic, or, you know, just a passion about mechanical keyboards, or something like that. But if you're people who chat kind of more on the regular for different things, maybe separate from a client project you're on or something like that, and you do find yourself exchanging a little bit more about, oh, you know, what you're doing in your life, or what are the things that are going on for you, that often does tend to build, I think, a deeper connection between colleagues, which can be really nice. STEPHANIE: Yeah. And I like that those relationships can also change. Like, there's different seasons in which you're more connected to some people and then less connected. Sometimes a colleague that you have shared interests with becomes someone that you kind of are in touch with more regularly, and then maybe you switch projects, and you aren't so much kind of as up to date. But, I don't know, I always think that there's, like, the right time for that kind of stuff, and it emerges. JOËL: I'm going to throw a bit of a buzzword at you, and I'd love to get your reaction. The idea of belonging, the feeling of belonging on a team, is that a good thing, something that we should seek out? And if so, how much of that is responsibility of, like, management or, like, a property of the team or the group to make you sort of feel that belonging? And how much of that is on you having to maybe disclose things about yourself or share a little bit of your personal life to, like, create that sense of belonging? STEPHANIE: Whoa. Yeah, that is a good way to frame it. I think there's a balance. There've been some, like, periods of my work life where I'm like, oh, I need more of a detachment from work and other times where I'm like, oh, I feel really disconnected, like, I want to feel like more of a part of this team. But I do think it's a management responsibility. And one thing that I know people to be cautious of is, you know, becoming too close at work. I don't know if your work being treated like a family, like, that kind of language can be a little bit borderline. JOËL: Almost manipulative. STEPHANIE: Right. Yeah, exactly. I do think there's something to be said about community at work and feeling like that kind of belonging, right? But also, that you can choose how much, like, you want to engage with that community and that being okay. I don't think it necessarily needs to be only through what you share about yourself. Like, you can have that sense of connection just by being a good colleague [chuckles], right? Like, even if the things you talk about are just within the realm of the project you're working on, like, there's still a sense of commitment and, yeah, in that relationship. And I think that is what matters when it comes to belonging. In the past, ways that I've seen that work well in regards to kind of how you share information is just, like, I don't know, share how you're doing. Like, you don't have to provide too many details. But it could be like, "Oh, I'm kind of distracted in my personal life right now, and that's why I wasn't able to get this done." People should be understanding of that, even if you don't kind of let them in on the more personal aspects of it. JOËL: Right. And you don't have to give any details, right? STEPHANIE: Yeah. JOËL: You should be in a place where people are comfortable with not knowing and not be like, "Ooh, what's going on with Stephanie's life? " STEPHANIE: [laughs] Yeah. But I do also think, like, the knowing that, like, something is going on is, like, also important context, right? Because you don't necessarily want that to impact the commitments you do have at work. JOËL: Right. And people tend to be a little bit more understanding if you're having to maybe shift some meetings around, or if you're struggling to focus on a particular day, or something like that. STEPHANIE: Yeah. 100%. JOËL: Yeah, we should normalize it of just like, "Hey, I'm having a hard day. I don't want to give details, but you know." STEPHANIE: Yeah. Yeah. I think a way that that is always kind of weird is how people communicate they're taking a sick day [laughs]. I actually had someone tell me that they really appreciated a time when I just said, "You know, I need to take care of myself today," and didn't really say anything else [laughs] about why. Because they're like, "Oh, like, that helped normalize this idea that, like, that is fine just kind of as is." There's no need to, you know, supply any additional reasoning. JOËL: Sometimes I feel like people almost feel the need to like, justify taking sick time. So, you've got to, like, say just how bad things are that now I'm actually taking sick time. STEPHANIE: Yeah, which is...that's not the point, right? You know, we have it because we need it [laughs]. So, yeah, I'm glad you mentioned that because I think that's actually a really good example of the ways that people, like, approach kind of bringing themselves to work like that. JOËL: Yeah, sometimes it's setting a boundary. An aspect I'm curious to look at is you, and I do a little bit of this with this podcast, right? Every week, we share a little bit of what's new in our world, and it goes out into the public internet. How do you tend to pick those topics and, like, how personal are you willing to get? STEPHANIE: Yeah. Oh, that's so hard. It's always hard [laughs], I think. I generally am pretty open. You know, I have talked about plans that I have for moving. I don't know, things about my gardening. I think I've also been a little vulnerable on the show before when I've, like, had a challenge, like, at work. But yeah, it's important, to me, I think, to be, like, true. Like, I think part of what our listeners like about this show is that we show up every week, and it's just a chat between two friends [laughs]. JOËL: Uh-huh. STEPHANIE: It also is kind of weird to know that it's just, like, out there, right? And I don't really know who's listening on the other side. I do know that, like, a lot of my friends listen. And, in some ways, I like to think that I'm talking to them, right? But yeah, sometimes I think about just, like, in a decade [laughs], it will still be out there. And on one hand, I think maybe it's kind of cool because I can listen back and be like, oh, like, that's what was going on for me in 2024. And other times I'm like, oh my God, what if I'm one day just, like, deeply embarrassed by things I've talked about on this show [laughs]? But that's a risk, I guess, I'm willing to take because I do think that the sense of connection that we foster with our audience is really meaningful. And it gives me a lot of joy whenever I meet a listener who's like, "Oh, you, you know, talked about this one thing, and I really related to it." And yeah, I guess that's what I do this for. What about you? JOËL: Yeah, I think kind of similar to you; tend to talk about things at work, interesting technical challenges, interesting sort of work, or even sometimes client-related challenges. Of course, you know, never calling out any clients by name, you know, talk about some hobbies and things like that. I think where I tend to draw the line a little bit is things that are a little bit more people-oriented in my personal life. So, I tend to not talk about family, and friends, and relationships, and things like that. And, you know, there are some times where there's like, those things intermix a little bit, where I'll, like, have shared, like, "This is what's new in my world." And then, like, off air, I'll follow up with you and say, "So, I didn't tell the whole story on air. STEPHANIE: [laughs] Yeah. JOËL: Here's what actually happened." Or, you know, "Here's this extra anecdote that I wanted you to know, but I didn't want everyone in the audience to hear." STEPHANIE: Yeah. I think the weirdest part for me, too, is I certainly have my, like, parasocial relationships with people that I follow on the internet [laughs], like, people on YouTube, or other podcasts, and stuff like that. But I haven't thought a whole lot about just, like, what that looks like for me as a host of a podcast. I think, kind of the size of the show now it feels right for me, where it's like I run into people who listen at conferences and stuff like that, but it is kind of contained to a work-related thing. So, that feels good because it, I think, for me, helps just give the work stuff a little bit of a deeper meaning, but otherwise isn't spilling over to my regular life. JOËL: And it's always fun when, you know, we get a listener email connecting to, you know, one of the random hobbies or something we've talked about and sharing a little bit of their experiences. I think last spring, I talked about getting a pair of bike shorts and, like, trying it out and seeing how that worked. And a listener called in and shared their experience with bike shorts, and, like, that's a lot of fun. It kind of creates that connection. So, I do enjoy that aspect. STEPHANIE: Yeah. And just to plug, you can write in to us at hosts@bikeshed.fm, and if you have anything you want to share that was inspired by what you heard us talk about on the show. JOËL: We'd love to have you. STEPHANIE: On that note, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at: tbot.io/referral. Or you can email us at: referrals@thoughtbot.com with any questions.
Stephanie shares an intriguing discovery about the origins of design patterns in software, tracing them back to architect Christopher Alexander's ideas in architecture. Joël is an official member of the Boston bike share system, and he loves it. He even got a notification on the app this week: "Congratulations. You have now visited 10% of all docking stations in the Boston metro area." #AchievementUnlocked, Joël! Joël and Stephanie transition into a broader discussion on data modeling within software systems, particularly how entities like companies, employees, and devices interconnect within a database. They debate the semantics of database relationships and the practical implications of various database design decisions, providing insights into the complexities of backend development. Christopher Alexander and Design Patterns (https://www.designsystems.com/christopher-alexander-the-father-of-pattern-language/) Rails guide to choosing between belongsto and hasone (https://edgeguides.rubyonrails.org/association_basics.html#choosing-between-belongs-to-and-has-one) Making impossible states impossible (https://www.youtube.com/watch?v=IcgmSRJHu_8) Transcript: We're excited to announce a new workshop series for helping you get that startup idea you have out of your head and into the world. It's called Vision to Value. Over a series of 90-minute working sessions, you'll work with a thoughtbot product strategist and a handful of other founders to start testing your idea in the market and make a plan for building an MVP. Join for all seven of the weekly sessions, or pick and choose the ones that address your biggest challenge right now. Learn more and sign up at tbot.io/visionvalue. JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. STEPHANIE: And I'm Stephanie Minn. And together, we're here to share a bit of what we've learned along the way. JOËL: So, Stephanie, what's new in your world? STEPHANIE: So, I learned a very interesting tidbit. I don't know if it's historical; I don't know if I would label it that. But, I recently learned about where the idea of design patterns in software came from. Are you familiar with that at all? JOËL: I read an article about that a while back, and I forget exactly, but there is, like, a design patterns movement, I think, that predates the software world. STEPHANIE: Yeah, exactly. So, as far as I understand it, there is an architect named Christopher Alexander, and he's kind of the one who proposed this idea of a pattern language. And he developed these ideas from the lens of architecture and building spaces. And he wrote a book called A Pattern Language that compiles, like, all these time-tested solutions to how to create spaces that meet people's needs, essentially. And I just thought that was really neat that software design adopted that philosophy, kind of taking a lot of these interdisciplinary ideas and bringing them into something technical. But also, what I was really compelled by was that the point of these patterns is to make these spaces comfortable and enjoyable for humans. And I have that same feeling evoked when I'm in a codebase that's really well designed, and I am just, like, totally comfortable in it, and I can kind of understand what's going on and know how to navigate it. That's a very visceral feeling, I think. JOËL: I love the kind of human-centric approach that you're using and the language that you're using, right? A place that is comfortable for humans. We want that for our homes. It's kind of nice in our codebases, too. STEPHANIE: Yeah. I have really enjoyed this framing because instead of just saying like, "Oh, it's quote, unquote, "best practice" to follow these design patterns," it kind of gives me more of a reason. It's more of a compelling reason to me to say like, "Following these design patterns makes the codebase, like, easier to navigate, or easier to change, or easier to work with." And that I can get kind of on board with rather than just saying, "This way is, like, the better way, or the superior way, or the way to do things." JOËL: At the end of the day, design patterns are a means to an end. They're not an end in of itself. And I think that's where it's very easy to get into trouble is where you're just sort of, I don't know, trying to rack up engineering points, I guess, for using a lot of design patterns, and they're not necessarily in service to some broader goal. STEPHANIE: Yeah, yeah, exactly. I like the way you put that. When you said that, for some reason, I was thinking about catching Pokémon or something like filling your Pokédex [laughs] with all the different design patterns. And it's not just, you know, like you said, to check off those boxes, but for something that is maybe a little more meaningful than that. JOËL: You're just trying to, like, hit the completionist achievement on the design patterns. STEPHANIE: Yeah, if someone ever reaches that, you know, gets that achievement trophy, let me know [laughs]. JOËL: Can I get a badge on GitHub for having PRs that use every single Gang of Four pattern? STEPHANIE: Anyway, Joël, what's new in your world? JOËL: So, on the topic of completing things and getting badges for them, I am a part of the Boston bike share...project makes it sound like it's a, I don't know, an exclusive club. It's Boston's bike share system. I have a subscription with them, and I love it. It's so practical. You can go everywhere. You don't have to worry about, like, a bike getting stolen or something because, like, you drop it off at a docking station, and then it's not your responsibility anymore. Yeah, it's very convenient. I love it. I got a notification on the app this week that said, "Congratulations. You have now visited 10% of all docking stations in the Boston metro area." STEPHANIE: Whoa, that's actually a pretty cool accomplishment. JOËL: I didn't even know they tracked that, and it's kind of cool. And the achievement shows me, like, here are all the different stations you've visited. STEPHANIE: You know what I think would be really fun? Is kind of the equivalent of a Spotify Wrapped, but for your biking in a year kind of around the city. JOËL: [laughs] STEPHANIE: That would be really neat, I think, just to be like, oh yeah, like, I took this bike trip here. Like, I docked at this station to go meet up with a friend in this neighborhood. Yeah, I think that would be really fun [laughs]. JOËL: You definitely see some patterns come up, right? You're like, oh yeah, well, you know, this is my commute into work every day. Or this is that one friend where, you know, every Tuesday night, we go and do this thing. STEPHANIE: Yeah, it's almost like a travelogue by bike. JOËL: Yeah. I'll bet there's a lot of really interesting information that could surface from that. It might be a little bit disturbing to find out that a company has that data on you because you can, like, pick up so much. STEPHANIE: That's -- JOËL: But it's also kind of fun to look at it. And you mentioned Spotify Wrapped, right? STEPHANIE: Right. JOËL: I love Spotify Wrapped. I have so much fun looking at it every year. STEPHANIE: Yeah. It's always kind of funny, you know, when products kind of track that kind of stuff because it's like, oh, like, it feels like you're really seen [laughs] in terms of what insights it's able to come up with. But yeah, I do think it's cool that you have this little badge. I would be curious to know if there's anyone who's, you know, managed to hit a hundred percent of all the docking stations. They must be a Boston bike messenger or something [laughs]. JOËL: Now that I know that they track it, maybe I should go for completion. STEPHANIE: That would be a very cool flex, in my opinion. JOËL: [laughs] And, you know, of course, they're always expanding the network, which is a good thing. I'll bet it's the kind of thing where you get, like, 99%, and then it's just really hard to, like, keep up. STEPHANIE: Yeah, nice. JOËL: But I guess it's very appropriate, right? For a podcast titled The Bike Shed to be enthusiastic about a bike share program. STEPHANIE: That's true. So, for today's topic, I wanted to pick your brain a little bit on a data modeling question that I posed to some other developers at thoughtbot, specifically when it comes to associations and associations through other associations [laughs]. So, I'm just going to kind of try to share in words what this data model looks like and kind of see what you think about it. So, if you had a company that has many employees and then the employee can also have many devices and you wanted to be able to associate that device with the company, so some kind of method like device dot company, how do you think you would go about making that association happen so that convenience method is available to you in the code? JOËL: As a convenience for not doing device dot employee dot company. STEPHANIE: Yeah, exactly. JOËL: I think a classic is, at least the other way, is that it has many through. I forget if you can do a belongs to through or not. You could also write, effectively, a delegation method on the device to effectively do dot employee dot company. STEPHANIE: Yeah. So, I had that same inkling as you as well, where at first I tried to do a belongs to through, but it turns out that belongs to does not support the through option. And then, I kind of went down the next path of thinking about if I could do a has one, a device has one company through employee, right? But the more I thought about it, the kind of stranger it felt to me in terms of the semantics of saying that a device has a company as opposed to a company having a device. It made more sense in plain English to think about it in terms of a device belonging to a company. JOËL: That's interesting, right? Because those are ways of describing relationships in sort of ActiveRecord's language. And in sort of a richer situation, you might have all sorts of different adjectives to describe relationships. Instead of just belongs to has many, you have things like an employee owns a device, an employee works for a company, you know because an employee doesn't literally belong to a company in the literal sense. That's kind of messed up. So, I think what ActiveRecord's language is trying to use is less trying to, like, hit maybe, like, the English domain language of how these things relate to, and it's more about where the foreign keys are in the database. STEPHANIE: Yeah. I like that point where even though, you know, these are the things that are available to us, that doesn't actually necessarily, you know, capture what we want it to mean. And I had gone to see what Rails' recommendation was, not necessarily for the situation I shared. But they have a section for choosing between which model should have the belongs to, as opposed to, like, it has one association on it. And it says, like you mentioned, you know, the distinction is where you place the foreign key, but you should kind of think about the actual meaning of the data. And, you know, we've talked a lot about, I think, domain modeling [chuckles] on the show. But their kind of documentation says that...the has something relationship says that one of something is yours, that it can, like, point back to you. And in the example I shared, it still felt to me like, you know, really, the device wanted to point to the company that it is owned by. And if we think about it in real-world terms, too, if that device, like, is company property, for example, then that's a way that that does make sense. But the couple of paths forward that I saw in front of me were to rework that association, maybe add a new column onto the device, and go down that path of codifying it at the database level. Or kind of maybe something as, like, an in-between step is delegating the method to the employee. And that's what I ended up doing because I wasn't quite ready to do that data migration. JOËL: Adding more columns is interesting because then you can run into sort of data consistency issues. Let's say on the device you have a company ID to see who the device belongs to. Now, there are sort of two different independent paths. You can ask, "Which company does this device belong to?" You can either check the company ID and then look it up in the company table. Or you can join on the employee and join the employee back under company. And those might give you different answers and that can be a problem with data consistency if those two need to stay in sync. STEPHANIE: Yeah, that is a good point. JOËL: There could be scenarios where those two are allowed to diverge, right? You can imagine a scenario where maybe a company owns the device, but an employee of a potentially different company is using the device. And so, now it's okay to have sort of two different chains because the path through the employee is about what company is using our devices versus which company actually owns them. And those are, like, two different kinds of relationships. But if you're trying to get the same thing through two different paths of joining, then that can set you up for some data inconsistency issues. STEPHANIE: Wow. I really liked what you said there because I don't think enough thought goes into the emergent relationships between models after they've been introduced to a codebase. At least in my experience, I've seen a lot of thought go up front into how we might want to model an ActiveRecord, but then less thought into seeing what patterns kind of show up over time as we introduce more functionality to these models, and kind of understand how they should exist in our codebase. Is that something that you find yourself kind of noticing? Like, how do you kind of pick up on the cue that maybe there's some more thought that needs to happen when it comes to existing database tables? JOËL: I think it's something that definitely is a bit of a red flag, for me, is when there are multiple paths to connect to sort of establish a relationship. So, if I were to draw out some sort of, like, diagram of the models, boxes, and arrows or something like that, and then I could sort of overlay different paths through that diagram to connect two models and realize that those things need to be in sync, I think that's when I started thinking, ooh, that's a potential danger. STEPHANIE: Yeah, that's a really great point because, you know, the example I shared was actually a kind of contrived one based on what I was seeing in a client codebase, not, you know, I'm not actually working with devices, companies, and employees [laughs]. But it was encoded as, essentially, a device having one company. And I ended up drawing it out because I just couldn't wrap my head around that idea. And I had, essentially, an arrow from device pointing to company when I could also see that you could go take the path of going through employee [laughs]. And I was just curious if that was intentional or was it just kind of a convenient way to have that direct method available? I don't currently have enough context to determine but would be something I want to pay attention to. Like you said, it does feel like, if not a red flag, at least an orange one. JOËL: And there's a whole kind of science to some of this called database normalization, where they're sort of, like, they all have rather arcane names. They're the first normal form, the second normal form, the third normal form, you know, it goes on. If you look at the definition, they're all also a little bit arcane, like every element in a relation must depend solely upon the primary key. And you're just like, well, what does that mean? And how do I know if my table is compliant with that? So, I think it's worth, if you're Googling for some of these, find an article that sort of explains these a little bit more in layman's terms, if you will. But the general idea is that there are sort of stricter and stricter levels of the amount of sort of duplicate sources of truth you can have. In a sense, it's almost like DRY but for databases, and for your database schema in particular. Because when you have multiple sources of truth, like who does this device belong to, and now you get two different answers, or three different answers, now you've got a data corruption issue. Unlike bugs in code where it's, you know, it can be a problem because the site is down, or users have incorrect behavior, but then you can fix it later, and then go to production, and disruption to your clients is the worst that happened, this sort of problem in data is sometimes unrecoverable. Like, it's just, hey, -- STEPHANIE: Whoa, that sounds scary. JOËL: Yeah, no, data problems scare me in a way that code problems don't. STEPHANIE: Whoa. Could you...I think I interrupted you. But where were you going to go about once you have corrupted data? Like, it's unrecoverable. What happens then? JOËL: Because, like, if I look at the database, do I know who the real owner of this...if I want to fix it, let's say I fix my schema, but now I've got all this data where I've got devices that have two different owners, and I don't know which one is the real one. And maybe the answer is, I just sort of pick one and say, "Oh, the one that was through this association is sort of the canonical one, and we can just sort of ignore the other one." Do I have confidence in that decision? Well, maybe depending on some of the other context maybe, I'm lucky that I can have that. The doomsday scenario is that it's a little bit of one, a little bit of the other because there were different code paths that would write to one way or another. And there's no real way of knowing. If there's not too many devices, maybe I do an audit. Maybe I have to, like, follow up with all of my customers and say, "Hey, can you tell me which ones are really your devices?" That's not going to scale. Like, real worst case scenario, you almost have to do, like, a bit of a bankruptcy, where you say, "Hey, all the data prior to this date there's a bit of a question mark on it. We're not a hundred percent sure about it." And that does not feel great. So, now you're talking about mitigation strategies. STEPHANIE: Oof. Wow. Yeah, you did make it sound [laughs] very scary. I think I've kind of been on the periphery of a situation like this before, where it's not just that we couldn't trust the code. It's that we couldn't trust the data in the database either to tell us how things work, you know, for our users and should work from a product perspective. And I was on a previous client project where they had to, yeah, like, hire a bunch of people to go through that data and kind of make those determinations, like you said, to kind of figure out it out for, you know, all of these customers to determine the source of truth there. And it did not sound like an easy feat at all, right? That's so much time and investment that you have to put into that once you get to that point. JOËL: And there's a little bit of, like, different problems at different layers. You know, at the database layer, generally, you want all of that data to be really in a sort of single source of truth. Sometimes that makes it annoying to query because you've got to do all these joins. And so, there are various denormalization strategies that you can use to make that. Or sometimes it's a risk you're going to take. You're going to say, "Look, this table is not going to be totally normalized. There's going to be some amount of duplication, and we're comfortable with the risk if that comes up." Sometimes you also build layers of abstractions on top, so you might have your data sort of at rest in database tables fully normalized and separated out, but it's really clunky to query. So, you build out a database view on top of that that returns data in sort of denormalized fashion. But that's okay because you can always get your correct answer by querying the underlying tables. STEPHANIE: Wow. Okay. I have a lot of thoughts about this because I feel like database normalization, and I guess denormalization now, are skills that I am certainly not an expert at. And so, when it comes to, like, your average developer, how much do you think that people need to be thinking about this? Or what strategies do you have for, you know, a typical Rails dev in terms of how deep they should go [laughs]? JOËL: So, the classic advice is you probably want to go to, like, third to fourth normal form, usually three. There's also like 3.5 for some reason. That's also, I think, sometimes called BNF. Anyway, sort of levels of how much you normalize. Some of these things are, like, really, really basic things that Rails just builds into its defaults with that convention over configuration, so things like every table should have a primary key. And that primary key should be something that's fixed and unique. So, don't use something like combination of first name, last name as your primary key because there could be multiple people with the same name. Also, people change their names, and that's not great. But it's great that people can change their names. It's not great to rely on that as a primary key. There are things like look for repeating columns. If you've got columns in your schema with a number prefix at the end, that's probably a sign that you want to extract a table. So, I don't know, you have a movie, and you want to list the actors for a movie. If your movie table has actor 1, actor 2, actor 3, actor 4, actor 5, you know, like, all the way up to actor 20, and you're just like, "Yeah, no, we fill, like, actor 1 through N, and if there's any space left over, we just put nulls in those columns," that's a pretty big sign that, hey, why don't you instead have a, like, actor's table, and then make a, like, has many association? So, a lot of the, like, really basic normalization things, I think, are either built into Rails or built into sort of best practices around Rails. I think something that's really useful for developers to get as a sense beyond learning the actual different normal forms is think about it like DRY for your schema. Be wary of sort of multiple sources of truth for your data, and that will get you most of the way there. When you're designing sort of models and tables, oftentimes, we think of DRY more in terms of code. Do you ever think about that a little bit in terms of your tables as well? STEPHANIE: Yeah, I would say so. I think a lot of the time rather than references to another table just starting to grow on a certain model, I would usually lean towards introducing a join table there, both because it kind of encapsulates this idea that there is a connection, and it makes the space for that idea to grow if it needs to in the future. I don't know if I have really been disciplined in thinking about like, oh, you know, there should really...every time I kind of am designing my database tables, thinking about, like, there should only be one source of truth. But I think that's a really good rule of thumb to follow. And in fact, I can actually think of an example right now where we are a little bit tempted to break that rule. And you're making me reconsider [laughter] if there's another way of doing so. One thing that I have been kind of appreciative of lately is on my current client project; there's just, like, a lot of data. It's a very data-intensive and sensitive application. And so, when we introduce migrations, those PRs get tagged for review by someone over from the DevOps side, just to kind of provide some guidance around, you know, making sure that we're setting up our models to scale well. One of the things that he's been asking me on my couple of code changes I introduced was, like, when I introduced an index, like, it happened to be, like, a composite index with a couple of different columns, and the particular order of those columns mattered. And he kind of prompted me to, like, share what my use cases for this index were, just to make sure that, like, some thought went into it, right? Like, it's not so much that the way that I had done it was wrong, but just that I had, like, thought about it. And I like that as a way of kind of thinking about things at the abstraction that I need to to do my dev work day to day and then kind of mapping that to, like you were saying, those best practices around keeping things kind of performant at the database level. JOËL: I think there's a bit of a parallel world that people could really benefit from dipping a toe in, and that's sort of the typed programming world, this idea of making impossible states impossible or making illegal states unrepresentable. That in the sort of now it's not schemas of database tables or schemas of types that you're creating but trying to prevent data coming into a state where someone could plausibly construct an instance of your object or your type that would be nonsensical in the context of your app, kind of trying to lock that down. And I think a lot of the ways that people in those communities think about...in a sense, it's kind of like database normalization for developers. So, if you're not wanting to, like, dip your toe in more of the sort of database-centric world and, like, read an article from a DBA, it might be worthwhile to look at some of those worlds as well. And I think a great starting point for that is a talk by Richard Feldman called Making Impossible States Impossible. It's for the Elm language. And there are equivalents, I think, in many others as well. STEPHANIE: That's really cool that you are making that connection. I know we've kind of briefly talked about workshops in the past on the show. But if there were a workshop for, you know, that kind of database normalization for developers, I would be the first to sign up [laughs]. JOËL: Hint, hint, RailsConf idea. There's something from your original question that I think is interesting to circle back to, and that's the fact that it was awkward to work through in Ruby to do the work that you wanted to do because the tables were laid out in a certain way. And sometimes, there's certain ways that you need the tables to be in order to be sort of safe to represent data, but they're not the optimal way that we would like to interact with them at the Ruby level. And I think it's okay for not everything in Ruby to be 100% reflective of the structure of the tables underneath. ActiveRecord gives us a great pattern, but everything is kind of one-to-one. And it's okay to layer on some things on top, add some extra methods to build some, like, connections in Ruby that rely on this normalized data underneath but that make life easier for you, or they better just represent or describe the relationships that you have. STEPHANIE: 100%. I was really compelled by your idea of introducing helpers that use more descriptive adjectives for what that relationship is like. We've talked about how Rails abstracted things from the database level, you know, for our convenience, but that should not stop us from, like, leaning on that further, right? And kind of introducing our own abstractions for those connections that we see in our domain. So, I feel really inspired. I might even kind of reconsider the way I handled the original example and see what I can make of it. JOËL: And I think your original solution of doing the delegation is a great example of this as well. You want the idea that a device belongs to a company or has an association called company, and you just don't want to go through that long chain, or at least you don't want that to be visible as an implementation detail. So, in this case, you delegate it through a chain of methods in Ruby. It could also be that you have a much longer chain of tables, and maybe they don't all have associations in Rails and all that. And I think it would be totally fine as well to define a method on an object where, I don't know, a device, I don't know, has many...let's call it technicians, which is everybody who's ever touched this device or, you know, is on a log somewhere for having done maintenance. And maybe that list of technicians is not a thing you can just get through regular Rails associations. Maybe there's a whole, like, custom query underlying that, and that's okay. STEPHANIE: Yeah, as you were saying that, I was thinking about that's actually kind of, like, active models are the great spot to put those methods and that logic. And I think you've made a really good case for that. JOËL: On that note, shall we wrap up? STEPHANIE: Let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at: tbot.io/referral. Or you can email us at: referrals@thoughtbot.com with any questions.
Joël shares his experience with the dry-rb suite of gems, focusing on how he's been using contracts to validate input data. Stephanie relates to Joël's insights with her preparation for RailsConf, discussing her methods for presenting code in slides and weighing the aesthetics and functionality of different tools like VS Code and Carbon.sh. She also encounters a CI test failure that prompts her to consider the implications of enforcing specific coding standards through CI processes. The conversation turns into a discussion on managing coding standards and tools effectively, ensuring that automated systems help rather than hinder development. Joël and Stephanie ponder the balance between enforcing strict coding standards through CI and allowing developers the flexibility to bypass specific rules when necessary, ensuring tools provide valuable feedback without becoming obstructions. Transcript: AD: We're excited to announce a new workshop series for helping you get that startup idea you have out of your head and into the world. It's called Vision to Value. Over a series of 90-minute working sessions, you'll work with a thoughtbot product strategist and a handful of other founders to start testing your idea in the market and make a plan for building an MVP. Join for all seven of the weekly sessions, or pick and choose the ones that address your biggest challenge right now. Learn more and sign up at tbot.io/visionvalue. STEPHANIE: Hello and welcome to another episode of the Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: I've been working on a project that uses the dry-rb suite of gems. And one of the things we're doing there is we're validating inputs using this concept of a contract. So, you sort of describe the shape and requirements of this, like hash of attributes that you get, and it will then tell you whether it's valid or not, along with error messages. We then want to use those to eventually build some other sort of value object type things that we use in the app. And because there's, like, failure points at multiple places that you have to track, it gets a little bit clunky. And I got to thinking a little bit about, like, forget about the internal machinery. What is it that I would actually like to happen here? And really, what I want is to say, I've got this, like, bunch of attributes, which may or may not be correct. I want to pass them into a method, and then either get back a value object that I was hoping to construct or some kind of error. STEPHANIE: That sounds reasonable to me. JOËL: And then, thinking about it just a little bit longer, I was like, wait a minute, this idea of, like, unstructured input goes into a method, you get back something more structured or an error, that's kind of the broad definition of parsing. I think what I'm looking for is a parser object. And this really fits well with a style of processing popularized in the functional programming community called parse, don't validate the idea that you use a parser like this to sort of transform data from more loose to more strict values, values where you can have more assumptions. And so, I create an object, and I can take a contract. I can take a class and say, "Attempt to take the following attributes. If they're valid according to the construct, create this classroom." And it, you know, does a bunch of error handling and some...under the hood, dry-rb does all this monad stuff. So, I handled that all inside of the object, but it's actually really nice. STEPHANIE: Cool. Yeah, I had a feeling that was where you were going to go. A while back, we had talked about really impactful articles that we had read over the course of the year, and you had shared one called Parse, Don't Validate. And that heuristic has actually been stuck in my head a little bit. And that was really cool that you found an opportunity to use it in, you know, previously trying to make something work that, like, you weren't really sure kind of how you wanted to implement that. JOËL: I think I had a bit of a light bulb moment as I was trying to figure this out because, in my mind, there are sort of two broad approaches. There's the parse, don't validate where you have some inputs, and then you transform them into something stricter. Or there's more of that validation approach where you have inputs, you verify that they're correct, and then you pass them on to someone else. And you just say, "Trust me, I verified they're in the right shape." Dry-rb sort of contracts feel like they fit more under that validation approach rather than the parse, don't validate. Where I think the kind of the light bulb turned on for me is the idea that if you pair a validation step and an object construction step, you've effectively approximated the idea of parse, don't validate. So, if I create a parser object that says, in sort of one step, I'm going to validate some inputs and then immediately use them if they're valid to construct an object, then I've kind of done a parse don't validate, even though the individual building blocks don't follow that pattern. STEPHANIE: More like a parse and validate, if you will [laughs]. I have a question for you. Like, do you own those inputs kind of in your domain? JOËL: In this particular case, sort of. They're coming from a form, so yes. But it's user input, so never trust that. STEPHANIE: Gotcha. JOËL: I think you can take this idea and go a little bit broader as well. It doesn't have to be, like, the dry-rb-related stuff. You could do, for example, a JSON schema, right? You're dealing with the input from a third-party API, and you say, "Okay, well, I'm going to have a sort of validation JSON schema." It will just tell you, "Is this data valid or not?" and give you some errors. But what if you paired that with construction and you could create a little parser object, if you wanted to, that says, "Hey, I've got a payload coming in from a third-party API, validate it against this JSON schema, and attempt to construct this shopping cart object, and give me an error otherwise." And now you've sort of created a nice, little parse, don't validate pipeline which I find a really nice way to deal with data like that. STEPHANIE: From a user perspective, I'm curious: Does this also improve the user experience? I'm kind of wondering about that. It seems like it could. But have you explored that? JOËL: This is more about the developer experience. STEPHANIE: Got it. JOËL: The user experience, I think, would be either identical or, you know, you can play around with things to display better errors. But this is more about the ergonomics on the development side of things. It was a little bit clunky to sort of assemble all the parts together. And sometimes we didn't immediately do both steps together at the same time. So, you might sort of have parameters that we're like, oh, these are totally good, we promise. And we pass them on to someone else, who passes them on to someone else. And then, they might try to do something with them and hope that they've got the data in the right shape. And so, saying, let's co-locate these two things. Let's say the validation of the inputs and then the creation of some richer object happen immediately one after another. We're always going to bundle them together. And then, in this particular case, because we're using dry-rb, there's all this monad stuff that has to happen. That was a little bit clunky. We've sort of hidden that in one object, and then nobody else ever has to deal with that. So, it's easier for developers in terms of just, if you want to turn inputs into objects, now you're just passing them into one object, into one, like, parser, and it works. But it's a nicer developer experience, but also there's a little bit more safety in that because now you're sort of always working with these richer objects that have been validated. STEPHANIE: Yeah, that makes sense. It sounds very cohesive because you've determined that these are two things that should always happen together. The problems arise when they start to actually get separated, and you don't have what you need in terms of using your interfaces. And that's very nice that you were able to bundle that in an abstraction that makes sense. JOËL: A really interesting thing I think about abstractions is sometimes thinking of them as the combination of multiple other things. So, you could say that the combination of one thing and another thing, and all of a sudden, you have a new sort of combo thing that you have created. And, in this case, I think the combination of input validation and construction, and, you know, to a certain extent, error handling, so maybe it's a combination of three things gives you a thing you can call a parser. And knowing that that combination is a thing you can put a name on, I think, is really powerful, or at least it felt really powerful to me when that light bulb turned on. STEPHANIE: Yeah, it's kind of like the whole is greater than the sum of its parts. JOËL: Yeah. STEPHANIE: Cool. JOËL: And you and I did an episode on Specialized Vocabulary a while back. And that power of naming, saying that, oh, I don't just have a bunch of little atomic steps that do things. But the fact that the combination of three or four of them is a thing in and of itself that has a name that we can talk about has properties that we're familiar with, all of a sudden, that is a really powerful way to think about a system. STEPHANIE: Absolutely. That's very exciting. JOËL: So, Stephanie, what's new in your world? STEPHANIE: So, I am plugging away at my RailsConf talk, and I reached the point where I'm starting to work on slides. And this talk will be the first one where I have a lot of code that I want to present on my slides. And so, I've been playing around with a couple of different tools to present code on slides or, I guess, you know, just being able to share code outside of an editor. And the two tools I'm trying are...VS Code actually has a copy with syntax functionality in its command palette. And so, that's cool because it basically, you know, just takes your editor styling and applies it wherever you paste that code snippet. JOËL: Is that a screenshot or that's, like, formatted text that you can paste in, like, a rich text editor? STEPHANIE: Yeah, it's the latter. JOËL: Okay. STEPHANIE: That was nice because if I needed to make changes in my slides once I had already put them there, I could do that. But then the other tool that I was giving a whirl is Carbon.sh. And that one, I think, is pretty popular because it looks very slick. It kind of looks like a little Mac window and is very minimal. But you can paste your code into their text editor, and then you can export PNGs of the code. So, those are just screenshots rather than editable text. And I [chuckles] was using that, exported a bunch of screenshots of all of my code in various stages, and then realized I had a typo [laughs]. JOËL: Oh no! STEPHANIE: Yeah, so I have not got around to fixing that yet. That was pretty frustrating because now I would have to go back and regenerate all of those exports. So, that's kind of where I'm at in terms of exploring sharing code. So, if anyone has any other tools that they would use and recommend, I am all ears. JOËL: How do you feel about balancing sort of the quantity of code that you put on a slide? Do you tend to go with, like, a larger code slide and then maybe, like, highlight certain sections? Do you try to explain ideas in general and then only show, like, a couple of lines? Do you show, like, maybe a class that's got ten lines, and that's fine? Where do you find that balance in terms of how much code to put on a slide? Because I feel like that's always the big dilemma for me. STEPHANIE: Yeah. Since this is my first time doing it, like, I really have no idea how it's going to turn out. But what I've been trying is focusing more on changes between each slide, so the progression of the code. And then, I can, hopefully, focus more on what has changed since the last snippet of code we were looking at. That has also required me to be more fiddly with the formatting because I don't want essentially, like, the window that's containing the code to be changing sizes [laughs] in between slide transitions. So, that was a little bit finicky. And then, there's also a few other parts where I am highlighting with, like, a border or something around certain texts that I will probably pause and talk about, but yeah, it's tough. I feel like I've seen it done well, but it's a lot harder to and a lot more effort to [laughs] do in practice, I'm finding. JOËL: When someone does it well, it looks effortless. And then, when somebody does it poorly, you're like, okay, I'm struggling to connect with this talk. STEPHANIE: Yep. Yep. I hear that. I don't know if you would agree with this, but I get the sense that people who are able to make that look effortless have, like, a really deep and thorough understanding of the code they're showing and what exactly they think is important for the audience to pay attention to and understand in that given moment in their talk. That's the part that I'm finding a lot more work [laughs] because just thinking about, you know, the code I'm showing from a different lens or perspective. JOËL: How do you sort of shrink it down to only what's essential for the point that you're trying to make? And then, more broadly, not just the point you're trying to make on this one slide, but how does this one slide fit into the broader narrative of the story you're trying to tell? STEPHANIE: Right. So, we'll see how it goes for me. I'm sure it's one of those things that takes practice and experience, and this will be my first time, and we'll learn something from it. JOËL: That's exciting. So, this is RailsConf in Detroit this year, I believe, May 7th through 9th. STEPHANIE: Yep. That's right. So, recently on my client work, I encountered a CI failure on a PR of mine that I was surprised by. And basically, I had introduced a new association on a model, and this CI failure was saying like, "Hey, like, we see that you introduced this association. You should consider adding this to the presenter for this model." And I hadn't even known that that presenter existed [laughs]. So, it was kind of interesting to get a CI failure nudging me to consider if I need to be, like, making a different, you know, this other change somewhere else. JOËL: That's a really fun use of CI. Do you think that was sort of helpful for you as a newer person on that codebase? Or was it more kind of annoying and, like, okay, this CI is over the top? STEPHANIE: You know, I'm not sure [laughs]. For what it's worth, this presenter was actually for their admin dashboard, essentially. And so, the goal of what this workflow was trying to do was help folks who are using the admin dashboard have, like, all of the capabilities they need to do that job. And it makes sense that as you add behavior to your app, sometimes those things could get missed in terms of supporting, you know, not just your customers but developers, support product, you know, the other users of your app. So, it was cool. And that was, you know, something that they cared enough to enforce. But yeah, I think there maybe is a bit of a slippery slope or at least some kind of line, or it might even be pretty blurry around what should our test failures really be doing. JOËL: And CI is interesting because it can be a lot more than just tests. You can run all sorts of things. You can run a linter that fails. You could run various code quality tools that are not things like unit tests. And I think those are all valid uses of the CI process. What's interesting here is that it sounds like there were two systems that needed to stay in sync. And this particular CI check was about making sure that we didn't accidentally introduce code that would sort of drift apart in those two places. Does that sound about right? STEPHANIE: Yeah, that does sound right. I think where it gets a little fuzzy, for me, is whether that kind of check was for code quality, was for a standard, or for a policy, right? It was kind of saying like, hey, like, this is the way that we've enforced developers to keep those two things from drifting. Whereas I think that could be also handled in different ways, right? JOËL: Yeah. I guess in terms of, like, keeping two things in sync, I like to do that at almost, like, a code level, if possible. I mean, maybe you need a single source of truth, and then it just sort of happens automatically. Otherwise, maybe doing it in a way that will yell at you. So, you know, maybe there's a base class somewhere that will raise an error, and that will get caught by CI, or, you know, when you're manually testing and like, oh yeah, I need to keep this thing in sync. Maybe you can derive some things or get fancy with metaprogramming. And the goal here is you don't have a situation where someone adds a new file in one place and then they accidentally break an admin dashboard because they weren't aware that you needed these two files to be one-to-one. If I can't do it just at a code level, I have done that before at, like, a unit test level, where maybe there's, like, a constant somewhere, and I just want to assert that every item in this constant array has a matching entry somewhere else or something like that, so that you don't end up effectively crashing the site for someone else because that is broken behavior. STEPHANIE: Yeah, in this particular case, it wasn't necessarily broken. It was asking you "Hey, should this be added to the admin presenter?" which I thought was interesting. But I also hear what you're saying. It actually does remind me of what we were talking about earlier when you've identified two things that should happen, like mostly together and whether the code gives you affordances to do that. JOËL: So, one of the things you said is really interesting, the idea that adding to the presenter might have been optional. Does that mean that CI failed for you but that you could merge anyway, or how does that work? STEPHANIE: Right. I should have been more clear. This was actually a test failure, you know, that happened to be caught by CI because I don't run [laughs] the whole test suite locally. JOËL: But it's an optional test failure, so you're allowed to let that test fail. STEPHANIE: Basically, it told me, like, if I want this to be shown in the presenter, add it to this method, or if not, add it to...it was kind of like an allow list basically. JOËL: I see. STEPHANIE: Or an ignore list, yeah. JOËL: I think that kind of makes sense because now you have sort of, like, a required consistency thing. So, you say, "Our system requires you...whenever you add a file in this directory, you must add it to either an allow list or an ignore list, which we have set up in this other file." And, you know, sometimes you might forget, or sometimes you're new, and it's your first time adding a file in this directory, and you didn't remember there's a different place where you have to effectively register it. That seems like a reasonable check to have in place if you're relying on these sort of allow lists for other parts of the system, and you need to keep them in sync. STEPHANIE: So, I think this is one of the few instances where I might disagree with you, Joël. What I'm thinking is that it feels a bit weird to me to enforce a decision that was so far away from the code change that I made. You know, you're right. On one hand, I am newer to this codebase, maybe have less of that context of different features, things that need to happen. It's a big app. But I almost think this test reinforces this weird coupling of things that are very far away from each other [laughs]. JOËL: So, it's maybe not the test itself you object to rather than the general architecture where these admin presenters are relying on these other objects. And by you introducing a file in a totally different part of the app, there's a chance that you might break the admin, and that feels weird to you. STEPHANIE: Yeah, that does feel weird to me. And then, also that this implementation is, like, codified in this test, I guess, as opposed to a different kind of, like, acceptance test, rather than specifying specifically like, oh, I noticed, you know, you didn't add this new association or attribute to either the allow list or the ignore list. Maybe there is a more, like, higher level test that could steer us in keeping the features consistent without necessarily dictating, like, that it needs to happen in these particular methods. JOËL: So, you're talking something like doing an integration test rather than a unit test? Or are you talking about something entirely different? STEPHANIE: I think it could be an integration test or a system test. I'm not sure exactly. But I am wondering what options, you know, are out there for helping keeping standards in place without necessarily, like, prescribing too much about, like, how it needs to be done. JOËL: So, you used the word standard here, which I tend to think about more in terms of, like, code style, things like that. What you're describing here feels a little bit less like a standard and more of what I would call a code invariant. STEPHANIE: Ooh. JOËL: It's sort of like in this architecture the way we've set up, there must always be sort of one-to-one matching between files in this directory and entries in this array. Now, that's annoying because they're sort of, like, two different places, and they can vary independently. So, locking those two in sync requires you to do some clunky things, but that's sort of the way the architecture has been designed. These two things must remain one-to-one. This is an invariant we want in the app. STEPHANIE: Can you define invariant for me [laughs], the way that you're using it here? JOËL: Yeah, so something that is required to be true of all elements in this class of things, sort of a rule or a law that you're applying to the way that these particular bits of code need to behave. So, in this case, the invariant is every file in this directory must have a matching entry in this array. There's a lot of ways to enforce that. The sort of traditional idea is sort of pushing a lot of that checking...they'll sometimes talk about pushing errors to the left. So, if you can handle this earlier in the sort of code execution pipeline, can you do it maybe with a type system if you're in a type language? Can you do it with some sort of input validation at runtime? Some languages have the concept of contracts, so maybe you enforce invariants using that. You could even do something really ad hoc in Ruby, where you might say, "Hey, at boot time, when we load this particular array for the admin, just load this directory. Make sure that the entries in the array match the entries in the directory, and if they don't, raise an error." And I guess you would catch that probably in CI just because you tried to run your test suite, and you'd immediately get this boot error because the entries don't match. So, I guess it kind of gets [inaudible 22:36] CI, but now it's not really a dedicated test anymore. It's more of, like, a property of the system. And so, in this case, I've sort of shifted the error checking or the checking of this invariant more into the architecture itself rather than in, like, things that exercise the architecture. But you can go the other way and say, "Well, let's shift it out of the architecture into tests," or maybe even beyond that, into, like, manual QA or, you know, other things that you can do to verify it. STEPHANIE: Hmm. That is very compelling to me. JOËL: So, we've been talking so far about the idea of invariants, but the thing about invariants is that they don't vary. They're always true. This is a sort of fundamental rule of how this system works. The class of problems that I often struggle with how to deal with in these sorts of situations are rules that you only sometimes want to apply. They're not consistent. Have you ever run into things like that? STEPHANIE: Yeah, I have. And I think that's what was compelling to me about what you were sharing about code invariance because I wasn't totally convinced this particular situation was a very clear and absolute rule that had been decided, you know, it seemed a little bit more ambiguous. When you're talking about, like, applying rules that sometimes you actually don't want to apply, I think of things like linters, where we want to disable, you know, certain rules because we just can't get around implementing the way we want to while following those standards. Or maybe, you know, sometimes you just have to do something that is not accessible [laughs], not that that's what I would recommend, but in the case where there aren't other levers to change, you maybe want to disable some kind of accessibility check. JOËL: That's always interesting, right? Because sometimes, you might want, like, the idea of something that has an escape hatch in it, but that immediately adds a lot of complexity to things as well. This is getting into more controversial territory. But I read a really compelling article by Jeroen Engels about how being able to, like, locally disable your linter for particular methods actually makes your code, but also the linter itself, a worse tool. And it really kind of made me rethink a little bit of how I approach linters as a tool. STEPHANIE: Ooh. JOËL: And what makes sense in a linter. STEPHANIE: What was the argument for the linter being a worse tool by doing that? JOËL: You know, it's funny that you ask because now I can't remember, and it's been a little while since I've read the article. STEPHANIE: I'll have to revisit it after the show [laughs]. JOËL: Apparently, I didn't do the homework for this episode, but we'll definitely link to that article in the show notes. STEPHANIE: So, how do you approach either introducing a new rule to something like a linter or maybe reconsidering an existing rule? Like, how would you go about finding, like, consensus on that from your team? JOËL: That varies a lot by organizational culture, right? Some places will do it top-down, some of them will have a broader conversation and come to a consensus. And sometimes you just straight up don't get a choice. You're pulling in a tool like standard rb, and you're saying, "Look, we don't want to have a discussion about every little style thing, so whatever, you know, the community has agreed on for the standard rb linter is the style we're using. There are no discussions. Do what the linter tells you." STEPHANIE: Yeah, that's true. I think I have to adapt to whatever, you know, client culture is like when I join new projects. You know, sometimes I do see people being like, "Hey, I think it's kind of weird that we have this," or, "Hey, I've noticed, for example, oh, we're merging focused RSpec tests. Like, let's introduce a rule to make sure that that doesn't happen." I also think that a different approach is for those things not to be enforced at all by automation, but we, you know, there are still guidelines. I think the thoughtbot guides are an example of pretty opinionated guidelines around style and syntax. But I don't think that those kinds of things would, you know, ever be, like, enforced in a way that would be blocking. JOËL: Those are kind of hard because they're not as consistent as you would think, so it's not a rule you can apply every time. It's more of a, here's some things to maybe keep in mind. Or if you're writing code in this way, think about some of the edge cases that might happen, or don't default to writing it in this way because things might go wrong. Make sure you know what you're doing. I love the phrase, "Must be able to justify this," or sometimes, "Must convince your pair that this is okay." So, default to writing in style A, avoid style B unless you can have a compelling reason to do so and can articulate that on your PR or, you know, convince your pair that that's the right way to go. STEPHANIE: Interesting. It's kind of like the honor system, then [laughs]. JOËL: And I think that's sort of the general way when you're working with developers, right? There's a lot of areas where there is ambiguity. There is no single best way to do it. And so, you rely on people's expertise to build systems that work well. There are some things where you say, look, having conversations about these things is not useful. We want to have some amount of standardization or uniformity about certain things. Maybe there's invariance you want to hold. Maybe there's certain things we're, like, this should never get to production. Whenever you've got these, like, broad sweeping statements about things should be always true or never true, that's a great time to introduce something like a linting rule. When it's more up to personal judgment, and you just want to nudge that judgment one way or another, then maybe it's better to have something like a guide. STEPHANIE: Yeah, what I'm hearing is there is a bit of a spectrum. JOËL: For sure. From things that are always true to things that are, like, sometimes true. I think I'm sort of curious about the idea of going a level beyond that, though, beyond things like just code style or maybe even, like, invariance you want to hold or something, being able to make suggestions to developers based off the code that is written. So, now you're applying more like heuristics, but instead of asking a human to apply those heuristics at code review time and leave some comments, maybe there's a way to get automated feedback from a tool. STEPHANIE: Yeah, I think we had mentioned code analysis tools earlier because some teams and organizations include those as part of their CI builds, right? And, you know, even Brakeman, right? Like, that's an analysis tool for security. But I can't recall if I've seen an organization use things like Flog metrics which measure code complexity in things like that. How would you feel if that were a check that was blocking your work? JOËL: So, I've seen things like that be used if you're using, like, the Code Climate plugin for GitHub. And Code Climate internally does effectively flog and other things that are fancier on your code quality. And so, you can set a threshold to say, hey, if complexity gets higher than a certain amount, fail the build. You can also...if you're doing things via GitHub, what's nice is that you can do effectively non-blocking comments. So, instead of failing CI to say, "Hey, this method looks really complex. You cannot merge until you have made this method less complex," maybe the sort of, like, next step up in ambiguity is to just leave a comment on a PR from a tool and say, "Hey, this method here is looking really complex. Consider breaking it up." STEPHANIE: Yeah, there is a tool that I've seen but not used called Danger, and its tagline is, Stop saying, "You forgot to..." in code review [laughs]. And it basically does that, what you were saying, of, like, leaving probably a suggestion. I can imagine it's blocking, but a suggestive comment that just automates that rather than it being a manual process that humans have to remember or notice. JOËL: And there's a lot of things that could be specific to your organization or your architecture. So, you say, "Hey, you introduced a file here. Would you consider also making an entry to this presenter file so that it's editable on the admin?" And maybe that's a better place to handle that. Just a comment. But you wouldn't necessarily want every code reviewer to have to think about that. STEPHANIE: So, I do think that I am sometimes not necessarily suspicious, but I have also seen tools like that end up just getting in the way, and it just becomes something you ignore. It's something you end up always using the escape hatch for, or people just find ways around it because they're harming more than they're helping. Do you have any thoughts about how to kind of keep those things in check and make sure that the tools we introduce genuinely are kind of helping the organization do the right thing rather than kind of being these perhaps arbitrary blockers? JOËL: I'm going to throw a fancy phrase at you. STEPHANIE: Ooh, I'm ready. JOËL: Signal-to-noise ratio. STEPHANIE: Whoa, uh-huh. JOËL: So, how often is the feedback from your tool actually helpful, and how often is it just noise that you have to dismiss, or manually override, or things like that? At some point, the ratio becomes so much that you lose the signal in all the noise. And so, maybe you even, like, because you're always just ignoring the feedback from this tool, you accidentally start overriding things that would be genuinely helpful. And, at that point, you've got the worst of both worlds. So, sort of keeping track on what that ratio is, and there's not, like, a magic number. I'm not going to tell you, "Oh, this is an 80/20 principle. You need to have, you know, 80% of the time it's useful and only 20% of the time it's not useful." I don't have a number to give you, but keeping track on maybe, you know, is it more often than not useful? Is your team getting to the point where they're just ignoring feedback from this tool? And thinking in terms of that signal versus that noise, I think is useful—to go back to that word again, heuristic for managing whether a tool is still helpful. STEPHANIE: Yeah. And I would even go on to say that, you know, I always appreciate when people in leadership roles keep an eye on these things. And they're like, "Oh, I've been hearing that people are just totally numb to this tool [laughs]" or, you know, "There's no engagement on this. People are just ignoring those signals." Any developer impacted by this, it is valid to bring it up if you're getting frustrated by it or just finding yourself, you know, having all of these obstacles getting in the way of your development process. JOËL: Sometimes, this can be a symptom that you're mixing too many classes of problems together in one tool. So, maybe there are things that are, like, really dangerous to your product to go live with them. Maybe it's, you know, something like Brakeman where you're doing security checks, and you really, ideally, would not go to production with a failing security check. And then, you've got some random other style things in there, and you're just like, oh yeah, whatever, it's this tool because it's mostly style things but occasionally gives you a security problem. And because you ignore it all the time, now you accidentally go to production with a security problem. So, splitting that out and say, "Look, we've got blocking and unblocking because we recognize these two classes of problems can be a helpful solution to this problem." STEPHANIE: Joël, did you just apply an object-oriented design principle to an organizational system? [laughter] JOËL: I may be too much of a developer. STEPHANIE: Cool. Well, I really appreciate your input on this because, you know, I was just kind of mulling over, like, how I felt about these kinds of things that I encounter as a developer. And I am glad that we got to kind of talk about it. And I think it gives me a more expanded vocabulary to, you know, analyze or reflect when I encounter these things on different client organizations. JOËL: And every organization is different, right? Like, you've got to learn the culture, learn the different elements of that software. What are the things that are invariant? What are the things that are dangerous that we don't want to ship without? What are the things that we're doing just for consistency? What are things which are, like, these are culturally things that we'd like to do? There's all these levels, and it's a lot to pick up. STEPHANIE: Yeah. At the end of the day, I think what I really liked about the last thing you said was being able to identify the problem, like the class of problem, and applying the right tool for the right job. It helps me take a step back and perhaps even think of different solutions that we might not have thought about earlier because we had just gotten so used to the one way of enforcing or checking things like that. JOËL: On that note, shall we wrap up? STEPHANIE: Let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeee!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at: tbot.io/referral. Or you can email us at: referrals@thoughtbot.com with any questions.
Joël conducted a thoughtbot mini-workshop on query plans, which Stephanie found highly effective due to its interactive format. They then discuss the broader value of interactive workshops over traditional talks for deeper learning. Addressing listener questions, Stephanie and Joël explore the strategic use of if and else in programming for clearer code, the importance of thorough documentation in identifying bugs, and the use of Postgres' EXPLAIN ANALYZE, highlighting the need for environment-specific considerations in query optimization. Episode mentioning query plans (https://bikeshed.thoughtbot.com/418) Query plan visualizer (https://explain.dalibo.com/) RailsConf 2024 (https://railsconf.org/) Episode 349: Unpopular Opinions (https://bikeshed.thoughtbot.com/349) Squint test (https://www.youtube.com/watch?v=8bZh5LMaSmE) Episode 405: Retro on Sandi Metz rules (https://bikeshed.thoughtbot.com/405) Structuring conditionals in a wizard (https://thoughtbot.com/blog/structuring-conditionals-in-a-wizard) Episode 417: Module docs (https://bikeshed.thoughtbot.com/417) Episode 416: Multidimensional numbers (https://bikeshed.thoughtbot.com/416) ruby-units gem (https://github.com/olbrich/ruby-units) Solargraph (https://marketplace.visualstudio.com/items?itemName=castwide.solargraph) parity (https://github.com/thoughtbot/parity) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville, and together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: Just recently, I ran a sort of mini workshop for some colleagues here at thoughtbot to dig into the idea of query plans and, how to read them, how to use them. And, initially, this was going to be more of a kind of presentation style. And a colleague and I who were sharing this decided to go for a more interactive format where, you know, this is a, like, 45-minute slot. And so, we set it up so that we did a sort of intro to query plans in about 10 minutes then 15 minutes of breakout rooms, where people got a chance to have a query plan. And they had some sort of comprehension questions to answer about it. And then, 15 minutes together to have each group share a little bit about what they had discovered in their query plan back with the rest of the group, so trying to balance some understanding, some application, some group discussion, trying to keep it engaging. It was a pretty fun approach to sharing information like that. STEPHANIE: Yeah. I wholeheartedly agree. I got to attend that workshop, and it was really great. Now that I'm hearing you kind of talk about the three different components and what you wanted people attending to get out of it, I am impressed because [laughs] there is, like, a lot more thought, I think, that went into just participant engagement that reflecting on it now I'm like, oh yeah, like, I think that was really effective as opposed to just a presentation. Because you had, you know, sent us out into breakout rooms, and each group had a different query that they were analyzing. You had kind of set up links that had the query set up in the query analyzer. I forget what the tool was called that you used. JOËL: I forget the name of it, but we will link it in the show notes. STEPHANIE: Yeah. It was helpful for me, though, because, you know, I think if I were just to have learned about it in a presentation or even just looked at, you know, screenshots of it on a slide, that's different still from interacting with it and feeling more confident to use it next time I find myself in a situation where it might be helpful. JOËL: It's really interesting because that was sort of the goal of it was to make it a bit more interactive and then, hopefully, helping people to retain more information than just a straight up, like, presentation would be. I don't know how you feel, I find that often when I go to a place like, let's say, RailsConf, I tend to stay away from more of the workshop-y style events and focus more on the talks. Is that something that you do as well? STEPHANIE: Yeah. I have to confess that I've never attended a workshop [laughs] at a conference. I think it's partly my learning style and also partly just honestly, like, my energy level when I'm at the conference. I kind of just want to sit back. It's on my to-do list. Like, I definitely want to attend one just to see what it's like. And maybe that might even inspire me to want to create my own workshop. But it's like, once I'm in it, and, you know, like, everyone else is also participating, I'm very easily peer pressured [laughs]. So, in a group setting, I will find myself enjoying it a lot more. And I felt that kind of same way with the workshop you ran for our team. Though, I will say a funny thing that happened was that when I went out into my breakout group with another co-worker, and we were trying to grok this query that you gave us, we found out that we got the hardest one, the most complicated one [laughs] because there were so many things going on. There was, like, multiple, like, you know, unions, some that were, like, nested, and then just, like, a lot of duplication as well, like, some conditions that were redundant because of a different condition happening inside of, like, an inner statement. And yeah, we were definitely scratching our heads for a bit and were very grateful that we got to come back together as a group and be like, "Can someone please help? [laughs] Let's figure out what's going on here." JOËL: Sort of close that loop and like, "Hey, here's what we saw. What does everybody else see?" STEPHANIE: Yeah, and I appreciated that you took queries from actual client projects that you were working on. JOËL: Yeah, that was the really fun part of it was that these were not sort of made-up queries to illustrate a point. These were actual queries that I had spent some time trying to optimize and where I had had to spend a lot of time digging into the query plans to understand what was going on. And it sounds like, for you, workshops are something that is...they're generally more engaging, and you get more value out of them. But there's higher activation energy to get started. Does that sound right? STEPHANIE: Yeah, that sounds right. I think, like, I've watched so many talks now, both in person and on YouTube, that a lot of them are easily forgettable [laughs], whereas I think a workshop would be a lot more memorable because of that interactivity and, you know, you get out of it what you put in a little bit. JOËL: Yeah, that's true. Have you looked at the schedule for RailsConf 2024 yet? And are there any workshops on there that you're maybe considering or that maybe have piqued your interest? STEPHANIE: I have, in fact, and maybe I will check off attending a workshop [laughs] off my bucket list this year. There are two that I'm excited about. Unfortunately, they're both at the same time slot, so I -- JOËL: Oh no. You're going to have to choose. STEPHANIE: I know. I imagine I'll have to choose. But I'm interested in the Let's Extend Rails With A Gem by Noel Rappin and Vision For Inclusion Workshop run by Todd Sedano. The Rails gem one I'm excited about because it's just something that I haven't had to do really in my dev career so far, and I think I would really appreciate having that guidance. And also, I think that would be motivation to just get that, like, hands-on experience with it. Otherwise, you know, this is something that I could say that I would want to do and then never get [chuckles] around to it. JOËL: Right, right. And building a gem is the sort of thing that I think probably fits better in a workshop format than in a talk format. STEPHANIE: Yeah. And I've really appreciated all of Noel's content out there. I've found it always really practical, so I imagine that the workshop would be the same. JOËL: So, other than poring over the RailsConf schedule and planning your time there, what has been new for you this week? STEPHANIE: I have a really silly one [laughs]. JOËL: Okay. STEPHANIE: Which is, yesterday I went out to eat dinner to celebrate my partner's birthday, and I experienced, for the first time, robots [laughter] at this restaurant. So, we went out to Hot Pot, and I guess they just have these, like, robot, you know, little, small dish delivery things. They were, like, as tall as me, almost, at least, like, four feet. They were cat-themed. JOËL: [laughs] STEPHANIE: So, they had, like...shaped like cat...they had cat ears, and then there was a screen, and on the screen, there was, like, a little face, and the face would, like, wink at you and smile. JOËL: Aww. STEPHANIE: And I guess how this works is we ordered our food on an iPad, and if you ordered some, like, side dishes and stuff, it would come out to you on this robot cat with wheels. JOËL: Very fun. STEPHANIE: This robot tower cat. I'm doing a poor job describing it because I'm still apparently bewildered [laughs]. But yeah, I was just so surprised, and I was not as...I think I was more, like, shocked than delighted. I imagine other people would find this, like, very fun. But I was a little bit bewildered [laughs]. The other thing that was very funny about this experience is that these robots were kind of going down the aisle between tables, and the aisles were not quite big enough for, like, two-way traffic. And so, there were times where I would be, you know, walking up to go use the restroom, and I would turn the corner and find myself, like, face to face with one of these cat robot things, and, like, it's starting to go at me. I don't know if it will stop [laughs], and I'm the kind of person who doesn't want to find out. JOËL: [laughs] STEPHANIE: So, to avoid colliding with this, you know, food delivery robot, I just, like, ran away from it [laughs]. JOËL: You don't know if they're, like, programmed to yield or something like that. STEPHANIE: Listen, it did not seem like it was going to stop. JOËL: [laughs] STEPHANIE: It got, like, I was, you know, kind of standing there frozen in paralysis [laughs] for a little while. And then, once it got, I don't know, maybe two or three feet away from me, I was like, okay, like, this is too close for comfort [laughs]. So, that was my, I don't know, my experience at this robot restaurant. Definitely starting to feel like I'm in the, I don't know, is this the future? Someone, please let me know [laughs]. JOËL: Is this a future that you're excited or happy about, or does this future seem a little bit dystopian to you? STEPHANIE: I was definitely alarmed [laughter]. But I'm not, like, a super early adopter of new technology. These kinds of innovations, if you will, always surprise me, and I'm like, oh, I guess this is happening now [laughs]. And I will say that the one thing I did not enjoy about it is that there was not enough room to go around this robot. It definitely created just pedestrian traffic issues. So, perhaps this could be very cool and revolutionary, but also, maybe design robots for humans first. JOËL: Or design your dining room to accommodate your vision for the robots. I'm sure that flying cars and robots will solve all of this, for sure. STEPHANIE: Oh yeah [laughter]. Then I'll just have to worry about things colliding above my head. JOËL: And for the listeners who cannot see my face right now, that was absolutely sarcasm [laughs]. Speaking of our listeners, today we're going to look at a group of different listener questions. And if you didn't know that, you could send in a question to have Stephanie and I discuss, you can do that. Just send us an email at hosts@bikeshed.fm. And sometimes, we put it into a regular episode. Sometimes, we combine a few and sort of make a listener question episode, which is what we're doing today. STEPHANIE: Yeah. It's a little bit of a grab bag. JOËL: Our first question comes from Yuri, and Yuri actually has a few different questions. But the first one is asking about Episode 349, which is pretty far back. It was my first episode when I was coming on with Chris and Steph, and they were sort of handing the baton to me as a host of the show. And we talked about a variety of hot takes or unpopular opinions. Yuri mentions, you know, a few that stood out to him: one about SPAs being not so great, one about how you shouldn't need to have a side project to progress in your career as a developer, one about developer title inflation, one about DRY and how it can be dangerous for a mid-level dev, avoiding let in RSpec specs, the idea that every if should come with an else, and the idea that developers shouldn't be included in design and planning. And Yuri's question is specifically the question about if statements, that every if should come with an else. Is that still an opinion that we still have, and why do we feel that way? STEPHANIE: Yeah, I'm excited to get into this because I was not a part of that episode. I was a listener back then when it was still Steph and Chris. So, I am hopefully coming in with a different, like, additional perspective to add as well while we kind of do a little bit of a throwback. So, the one about every if should come with an else, that was an unpopular opinion of yours. Do you mind kind of explaining what that means for you? JOËL: Yeah. So, in general, Ruby is an expression-oriented language. So, if you have an if that does not include an else, it will implicitly return nil, which can burn you. There may be some super expert programmers out there that have never run into undefined method for nil nil class, but I'm still the kind of programmer who runs into that every now and then. And so, implicit nils popping up in my code is not something I generally like. I also generally like having explicit else for control flow purposes, making it a little bit clearer where flow of control goes and what are the actual paths through a particular method. And then, finally, doing ifs and elses instead of doing them sort of inline or as trailing conditionals or things like that, by having them sort of all on each lines and balancing out. The indentation itself helps to scan the code a little bit more. So, deeper indentation tells you, okay, we're, like, nesting multiple conditions, or something like that. And so, it makes it a little bit easier to spot complexity in the code. You can apply, and I want to say this is from Sandi Metz, the squint test. STEPHANIE: Yeah, it is. JOËL: Where you just kind of, like, squint at your code so you're not looking at the actual characters, and more of the structure, and the indentation is actually a friend there rather than something to fight. So, that was sort of the original, I think, idea behind that. I'm curious, in your experience, if you would like to balance your conditionals, ifs with something else, or if you would like to do sort of hanging ifs. STEPHANIE: Hanging ifs, I like that phrase that you just coined there. I agree with your opinion, and I think it's especially true if you're returning values, right? I mean, in Ruby, you kind of always are. But if you are caring about return values, like you said, to avoid that implicit nil situation, I find, especially if you're writing tests for that code, it's really easy, you know, if you spot that condition, you're like, okay, great. Like, this is a path I need to test. But then, oftentimes, you don't test that implicit path, and if you don't enter the condition, then what happens, right? So, I think that's kind of what you're referring to when you talk about both. It's, like, easier to spot in terms of control flow, like, all the different paths of execution, as well as, yeah, like, saving you the headaches of some bugs down the line. One thing that I thought about when I was kind of revisiting that opinion of yours is the idea of like, what are you trying to communicate is different or special about this condition when you are writing an if statement? And, in my head, I kind of came up with a few different situations you might find yourself in, which is, one, where you truly just have, like, a special case, and you're treating that completely differently. Another when you have more of a, like, binary situation, where it's you want to kind of highlight either...more of a dichotomy, right? It's not necessarily that there is a default but that these are two opposite things. And then, a third situation in which you have multiple conditions, but you only happen to have two right now. JOËL: Interesting. And do you think that, like, breaking down those situations would lead you to pick different structures for writing your conditionals? STEPHANIE: I think so. JOËL: Which of those scenarios do you think you might be more likely to reach for an if that doesn't have an else that goes with it? STEPHANIE: I think that first one, the special case one. And in Yuri's email, he actually asked, as a follow-up, "Do we avoid guard clauses as a result of this kind of heuristic or rule?" And I think that special case situation is where a guard clause would shine because you are highlighting it by putting it at the top of a method, and then saying like, you know, "Bail out of this" or, like, "Return this particular thing, and then don't even bother about the rest of this code." JOËL: I like that. And I think guard clauses they're not the first thing I reach for, but they're not something I absolutely avoid. I think they need to be used with care. Like you said, they have to be in the top of your method. If you're adding returns and things that break out of your method, deep inside a conditional somewhere, 20 lines into your method, you don't get to call that a guard clause anymore. That's something else entirely. I think, ideally, guard clauses are also things that will break out of the method, so they're maybe raising exception. Maybe they're returning a value. But they are things that very quickly check edge cases and bail so that the body of the method can focus on expecting data in the correct shape. STEPHANIE: I have a couple more thoughts about this; one is I'm reminded of back when we did that episode on kind of retroing Sandi Metz's Rules For Developers. I think one of the rules was: methods should only be five lines of code. And I recall we'd realized, at least I had realized for the first time, that if you write an if-else condition in Ruby, that's exactly five lines [laughs]. And so, now that I'm thinking about this topic, it's cool to see that a couple of these rules converge a little bit, where there's a bit of explicitness in saying, like, you know, if you're starting to have more conditions that can't just be captured in a five-line if-else statement, then maybe you need something else there, right? Something perhaps like polymorphic or just some way to have branched earlier. JOËL: That's true. And so, even, like, you were talking about the exceptional edge cases where you might want to bail. That could be a sign that your method is doing too much, trying to like, validate inputs and also run some sort of algorithm. Maybe this needs to be some sort of, like, two-step thing, where there's almost, like, a parsing phase that's handled by a different object or a different method that will attempt to standardize your inputs and raise the appropriate errors and everything. And then, your method that has the actual algorithm or code that you're trying to run can just assume that its inputs are in the correct shape, kind of that pushing the uncertainty to the edges. And, you know, if you've only got one edge case to check, maybe it's not worth to, like, build this in layers, or separate out the responsibilities, or whatever. But if you're having a lot, then maybe it does make sense to say, "Let's break those two responsibilities out into two places." STEPHANIE: Yeah. And then, the one last kind of situation I've observed, and I think you all talked about this in the Unpopular Opinions episode, but I'm kind of curious how you would handle it, is side effects that only need to be applied under a certain condition. Because I think that's when, if we're focusing less on return values and more just on behavior, that's when I will usually see, like, an if something, then do this that doesn't need to happen for the other path. JOËL: Yes. I guess if you're doing some sort of side effect, like, I don't know, making a request to an API or writing to a file or something, having, like, else return nil or some other sentinel value feels a little bit weird because now you're caring about side effects rather than return values, something that you need to keep thinking of. And that's something where I think my thing has evolved since that episode is, once you start having multiple of these, how do they compose together? So, if you've got if condition, write to a file, no else, keep going. New if condition, make a request to an API endpoint, no else, continue. What I've started calling independent conditions now, you have to think about all the different ways that they can combine, and what you end up having is a bit of a combinatorial explosion. So, here we've got two potential actions: writing to a file, making a request to an API. And we could have one or the other, or both, or neither could happen, depending on the inputs to your method, and maybe you actually want that, and that's cool. Oftentimes, you didn't necessarily want all of those, especially once you start going to three, four, five. And now you've got that, you know, explosion, like, two to the five. That's a lot of paths through your method. And you probably didn't really need that many. And so, that can get really messy. And so, sometimes the way that an if and an else work where those two paths are mutually exclusive actually cuts down on the total number of paths through your method. STEPHANIE: Hmm, I like that. That makes a lot of sense to me. I have definitely seen a lot of, like, procedural code, where it becomes really hard to tell how to even start relating some of these concepts together. So, if you happen to need to run a side effect, like writing to a file or, I don't know, one common one I can think of is notifying something or someone in a particular case, and maybe you put that in a condition. But then there's a different branching path that you also need to kind of notify someone for a similar reason, maybe even the same reason. It starts to become hard to connect, like, those two reasons. It's not something that, like, you can really scan for or, like, necessarily make that connection because, at that point, you're going down different paths, right? And there might be other signals that are kind of confusing things along the way. And it makes it a lot harder, I think, to find a shared abstraction, which could ultimately make those really complicated nested conditions a little more manageable or just, like, easier to understand at a certain complexity. I definitely think there is a threshold. JOËL: Right. And now you're talking about nested versus non-nested because when conditions are sort of siblings of each other, an if-else behaves differently from two ifs without an else. I think a classic situation where this pops up is when you're structuring code for a wizard, a multi-step form. And, oftentimes, people will have a bunch of checks. They're like, oh, if this field is present, do these things. If this field is present, do these things. And then, it becomes very tricky to know what the flow of control is, what you can expect at what moment, and especially which actions might get shared across multiple steps. Is it safe to refactor in one place if you don't want to break step three? And so, learning to think about the different paths through your code and how different conditional structures will impact that, I think, was a big breakthrough for me in terms of taking the next logical step in terms of thinking, when do I want to balance my ifs and when do I not want to? I wrote a whole article on the topic. We'll link it in the show notes. So, Yuri, thanks for a great question, bringing us back into a classic developer discussion. Yuri also asks or gives us a bit of a suggestion: What about revisiting this topic and doing an episode on hot takes or unpopular topics? Is that something that you'd be interested in, Stephanie? STEPHANIE: Oh yeah, definitely, because I didn't get to, you know, share my hot topics the last episode [laughs]. [inaudible 24:23] JOËL: You just got them queued up and ready to go. STEPHANIE: Yeah, exactly. So, yeah, I will definitely be brainstorming some spicy takes for the show. JOËL: So, Yuri, thanks for the questions and for the episode suggestion. STEPHANIE: So, another listener, Kevin, wrote in to us following up from our episode on Module Docs and about a different episode about Multi-dimensional Numbers. And he mentioned a gem that he maintains. It's called Ruby Units. And it basically handles the nitty gritty of unit conversions for you, which I thought was really neat. He mentioned that it has a numeric class, and it knows how to do math [laughs], which I would find really convenient because that is something that I have been grateful not to have to really do since college [laughs], at least those unit conversions and all the things that I'd probably learned in math and physics courses [laughs]. So, I thought that was really cool, definitely is one to check out if you frequently work with units. It seemed like it would be something that would make sense for a domain that is more science or deals in that kind of domain. JOËL: I'm always a huge fan of anything that tags raw numbers that you're working with with a quantity rather than just floating raw numbers around. It's so easy to make a mistake to either treat a number as a quantity you didn't think of, or make some sort of invalid operation on it, or even to think you have a value in a different size than you do. You think you're dealing with...you know you have a time value, but you think it's in seconds. It's actually in milliseconds. And then, you get off by some big factor. These are all mistakes that I have personally made in my career, so leaning on a library to help avoid those mistakes, have better information hiding for the things that really aren't relevant to the work that I'm trying to do, and also, kind of reify these ideas so that they have sort of a name, and they're, like, their own object, their own thing that we can interact with in the app rather than just numbers floating around, those are all big wins from my perspective. STEPHANIE: I also just thought of a really silly use case for this that is, I don't know, maybe I'll have to experiment with this. But every now and then, I find the need to have to convert a unit, and I just pop into Google, and I'm like, please give me, you know, I'll search for 10 kilometers in miles or something [laughs]. But then I have to...sometimes Google will figure it out for me, and sometimes it will just list me with a bunch of weird conversion websites that all have really old-school UI [laughs]. Do you know what I'm talking about here? Anyway, I would be curious to see if I could use this gem as a command-line interface [laughs] for me without having to go to my browser and roll the dice with freecalculator.com or something like that [laughs]. JOËL: One thing that's really cool with this library that I saw is the ability to define your own units, and that's a thing that you'll often encounter having to deal with values that are maybe not one of the most commonly used units that are out there, dealing with numbers that might mean a thing that's very particular to your domain. So, that's great that the library supports that. I couldn't see if it supports multi-dimensional units. That was the episode that inspired the comment. But either way, this is a really cool library. And thank you, Kevin, for sharing this with us. STEPHANIE: Kevin also mentions that he really enjoys using YARD docs. And we had done that whole episode on Module Docs and your experience writing them. So, you know, your people are out there [laughs]. JOËL: Yay. STEPHANIE: And we talked about this a little bit; I think that writing the docs, you know, on one hand, is great for future readers, but, also, I think has the benefit of forcing the author to really think about their inputs and outputs, as Kevin mentions. He's found bugs by simply just going through that process in designing his code, and also recommends Solargraph and Solargraph's VSCode extension, which I suspect really kind of makes it easy to navigate a complex codebase and kind of highlight just what you need to know when working with different APIs for your classes. So, I recently kind of switched to the Ruby LSP, build with Shopify, but I'm currently regretting it because nothing is working for me right now. So, that might be the push that I need [laughs] to go back to using Solargraph. JOËL: It's interesting that Kevin mentions finding bugs while writing docs because that has absolutely been my experience. And even in this most recent round, I was documenting some code that was just sort of there. It wasn't new code that I was writing. And so, I had given myself the rule that this would be documentation-only PRs, no code changes. And I found some weird code, and I found some code that I'm 98% sure is broken. And I had to have the discipline to just put a notice in the documentation to be like, "By the way, this is how the method should work. I'm pretty sure it's broken," and then, maybe come back to it later to fix it. But it's amazing how trying to document code, especially code that you didn't write yourself, really forces you to read it in a different way, interact with it in a different way, and really, like, understand it in a deep way that surprised me a little bit the first time I did it. STEPHANIE: That's cool. I imagine it probably didn't feel good to be like, "Hey, I know that this is broken, and I can't fix it right now," but I'm glad you did. That takes a lot of, I don't know, I think, courage, in my opinion [laughs], to be like, "Yeah, I found this, and I'm going to, you know, like, raise my hand acknowledging that this is how it is," as supposed to just hiding behind a broken functionality that no one [laughs] has paid attention to. JOËL: And it's a thing where if somebody else uses this method and it breaks in a way, and they're like, "Well, the docs say it should behave like this," that would be really frustrating. If the docs say, "Hey, it should behave like this, but it looks like it's broken," then, you know, I don't know, I would feel a little bit vindicated as a person who's annoyed at the code right now. STEPHANIE: For sure. JOËL: Finally, we have a message from Tim about using Postgres' EXPLAIN ANALYZE. Tim says, "Hey, Joël, in the last episode, you talked a bit about PG EXPLAIN ANALYZE. As you stated, it's a great tool to help figure out what's going on with your queries, but there is a caveat you need to keep in mind. The query planner uses statistics gathered on the database when making decisions about how to fetch records. If there's a big difference between your dev or staging database and production, the query may make different decisions. For example, if a table has a low number of records in it, then the query planner may just do a table scan, but in production, it might use an index. Also, keep in mind that after a schema changes, it may not know about new indexes or whatever unless an explicit ANALYZE is done on the table." So, this is really interesting because, as Tim mentions, EXPLAIN ANALYZE doesn't behave exactly the same in production versus in your local development environment. STEPHANIE: When you were trying to optimize some slow queries, where were you running the ANALYZE command? JOËL: I used a combination. I mostly worked off of production data. I did a little bit on a staging database that had not the same amount of records and things. That was pretty significant. And so, I had to switch to production to get realistic results. So, yes, I encountered this kind of firsthand. STEPHANIE: Nice. For some reason, this comment also made me think of..., and I wanted to plug a thoughtbot shell command that we have called Parity, which lets you basically download your production database into your local dev database if you use Heroku. And that has come in handy for me, obviously, in regular development, but would be really great in this use case. JOËL: With all of the regular caveats around security, and PII, and all this stuff that come with dealing with production data. But if you're running real productions on production, you should be cleared and, like, trained for access to all of that. I also want to note that the queries that you all worked with on Friday are also from the production database. STEPHANIE: Really? JOËL: So, you got to see what it actually does, what the actual timings were. STEPHANIE: I'm surprised by that because we were using, like, a web-based tool to visualize the query plans. Like, what were you kind of plugging into the tool for it to know? JOËL: So, the tool accepts a query plan, which is a text output from running a SQL query. STEPHANIE: Okay. So, it's just visualizing it. JOËL: Correct. Yeah. So, you've got this query plan, which comes back as this very intimidating block of, like, text, and arrows, and things like that. And you plug it into this web UI, and now you've got something that is kind of interactive, and visual, and you can expand or collapse nodes. And it gives you tooltips on different types of information and where you're spending the most time. So, yeah, it's just a nicer way to visualize that data that comes from the query plan. STEPHANIE: Gotcha. That makes sense. JOËL: So, that's a very important caveat. I don't think that's something that we mentioned on the episode. So, thank you, Tim, for highlighting that. And for all of our listeners who were intrigued by leaning into EXPLAIN ANALYZE and query plan viewers to debug your slow queries, make sure you try it out in production because you might get different results otherwise. STEPHANIE: So, yeah, that about wraps up our listener topics in recent months. On that note, Joël, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeeee!!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at: tbot.io/referral. Or you can email us at: referrals@thoughtbot.com with any questions.
Stephanie revisits the concept of "spiking"—a phase of exploration to determine the feasibility of a technical implementation or to address unknowns in feature requests—sharing her recent experiences with a legacy Rails application. Joël brings a different perspective by discussing his involvement with a client project that heavily utilizes the dry-rb suite of gems, highlighting the learning curve associated with adapting to new patterns and libraries. Joël used to be much more idealistic and has moved to be more pragmatic. Stephanie has moved the other way. So together, Stephanie and Joël engage in a philosophical discussion on being an idealistic versus a pragmatic programmer. They explore the concept of programming as a blend of science and art, where technical decisions are not only about solving problems but also about expressing ideas and building shared understandings within a team. Spike tasks episode (https://bikeshed.thoughtbot.com/414) dry-rb (https://dry-rb.org/) Working with Maybe talk (https://www.youtube.com/watch?v=43eM4kNbb6c) Problem solving with maybe (https://thoughtbot.com/blog/problem-solving-with-maybe) Programming as Theory Building (https://pablo.rauzy.name/dev/naur1985programming.pdf) The Pragmatic Programmer (https://pragprog.com/titles/tpp20/the-pragmatic-programmer-20th-anniversary-edition/) Transcript: JOËL: Hello and welcome to another episode of the Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. STEPHANIE: And I'm Stephanie Minn, and together, we're here to share a bit of what we've learned along the way. JOËL: So, Stephanie, what's new in your world? STEPHANIE: So, a few weeks ago, we did an episode on spiking in response to a listener question. And I wanted to kind of revisit that topic for a little bit because I've been doing a lot of spiking on my client project. And for those who are not familiar, the way that I understand or define spikes is kind of as an exploration phase to figure out if a technical implementation might work. Or if you have a feature request with some unknowns, you can spend some time-boxed spiking to figure out what those unknowns might be. And I'm working on your typical legacy Rails application [laughs]. And I think one thing that we talked about last time was this idea of, at what point does spiking end up being just working on the feature [laughs]? And I think that's especially true in an older codebase, where you kind of have to go down a few rabbit holes, maybe, just to even find out if something will trip you up down the line. And the way I approached that this time around was just, like, identifying the constraints and putting a little flag there for myself. Like, these were rabbit holes that I could go down, but, you know, towards the initial beginning phase of doing the spiking, I decided not to. I just kind of bookmarked it for later. And once I had identified the main constraints, that was when I was like, okay, like, what kind of solutions can I come up with for these constraints? And that actually then helped me kind of decide which ones we're pursuing a little bit more to get, like, the information I needed to ultimately make a decision about whether this was worth doing, right? It kind of kept me...I'm thinking about, you know, when you are bowling with those safety guards [laughs], it keeps your ball from just rolling into the gutter. I think it helped with not going too deep into places that I may or may not be super fruitful while also, I think, giving me enough information to have a more realistic understanding of, like, what this work would entail. JOËL: Would you say that this approach that you're taking is inspired or maybe informed by the conversation we had on the episode? STEPHANIE: I was especially interested in avoiding the kind of binary of like, no, we can't do this because the system just, you know, isn't able to support it, or it's just too...it would be too much work. That was something I was really, like you said, kind of inspired by after that conversation because I wanted to avoid that trap a little bit. And I think another really helpful framing was the idea of, like, okay, what would need to be done in order to get us to a place where this could be possible? And that's why I think identifying those constraints was important because they're not constraints forever. Like, we could do something about them if we really wanted to, so kind of avoiding the, like, it's not possible, right? And saying like, "It could be. Here's all the things that we need to do in order to make it possible." But I think that helped shift the conversation, especially with stakeholders and stuff, to be a little bit more realistic and collaborative. So, Joël, what's new in your world? JOËL: So, I'm also on a new client project, and a thing that's been really interesting in this codebase is that they've been using the dry-rb suite of gems pretty heavily. And I've seen a lot about the suite of gems. I've read about them. Interestingly, this is kind of the first time that I've been on a codebase that sort of uses them as a main pattern in the app. So, there's been a bit of a learning curve there, and it's been really interesting. STEPHANIE: This is exciting to me because I know you have a lot of functional programming background, also, so it's kind of surprising that you're only now, you know, using something that explicit from functional languages in Ruby. And I'm curious: what's the learning curve, if not the paradigm? Like, what are you kind of encountering? JOËL: I think there's a little bit of just the translation. How do these gems sort of approach this? So, they have to do a couple of, like, clever Ruby things to make some of these features work. Some of these also will have different method names, so a lot of just familiarizing myself with the libraries. Like, oh, well, this thing that I'm used to having called a particular thing has a slightly different name here or maybe not having all of the utilities. I was like, oh, how do we traverse with this particular library? Then you have to, like, look it up. So, it's a lot of like, how do I do this thing I know how to do in, let's say, Elm? How do I translate that into Ruby? But then, also, some of the interplay of how that works in code that also does some very kind of imperative side effecty things also written by a team that is getting used to the pattern. And so, you'll sort of see things where people are pulling things in, but maybe you don't fully understand the deeper underlying approach that's meant to be used. STEPHANIE: Have you noticed any use cases where the dry-rb patterns really shine in your application? JOËL: A thing that's nice is that I think it really forces you to think about your edge cases in a way that sometimes Ruby developers play very fast and loose with "Yeah, whatever, it will never be nil." Push to production immediately start getting NoMethodError in your bug tracker. I never do this, by the way, but you know. STEPHANIE: [laughs]. JOËL: Speaking from a friend's experience [laughs]. STEPHANIE: Asking for a friend, yeah [laughs]. JOËL: I think a thing that I've sort of had to figure out sort of every time I deal with these patterns in different languages is just the importance of good composition and good separation. Because you're adding these sort of wrapper context around things, if you're constantly wrapping and unwrapping, you're like, check things inside, and then do the next thing, and then unwrap again and branch and check and do the next thing, that code becomes really clunky in a way that you just sort of expect to do if you're just writing code in regular Ruby with a nil. But it doesn't really work with a dry-rb maybe or a result. So, the pattern that I have found that works really well is to extract sort of every operation that can be, let's say, that could fail so that it would give you a result back. Extract that out into its own separate function that will construct a success or a failure, and then have your sort of main code that wants to then do a bunch of these things together. All it does is use some of the dry-rb helper methods to compose all of these together, whether that's just some sort of, like, do notation, or binding, or fmap, or something like that, which allows you to have sort of individual chunks that can fail, and then one sort of aggregator piece of code that just finds a way to combine all of them nicely. And that avoids you having to do all this repetition. STEPHANIE: Yeah, that makes a lot of sense. JOËL: It's a pattern, I think; I had to learn the hard way when I was working with Elm. Because if you're taking a potential nullable value and then you want to do things with it but then that potential operation is also nullable because the input was potentially null, and then that just sort of propagates all the way down the chain. So, my whole chain of functions now is doing checks for nullability. And in Ruby, I could just be like, no, I checked it in the first function. I can then just trust that it's not null down the chain. Elm doesn't do the like, trust me, bro. The compiler will force you to validate every time, and then the code just blows up, and it gets really painful. So, I had to start thinking about new models of thinking that would separate out code that actually needs to care and code that doesn't need to care about nullability. And I wrote an article about that. That turned into actually a conference talk as well. And these sort of ideas have served me really well at Elm. And I think these translate pretty well to dry-rb as well. That's something that I'm exploring, but the principles seem like they're not tied to a particular language. STEPHANIE: Yeah, and it's kind of cool that you experienced all of that in working with Elm, where a compiler was there to yell at you [laughs] and kind of forcing you to...I don't know if do the right thing is the right word, but kind of think in the way that it wants you to think. And I can see people who are coming from Ruby and starting to experiment with dry-rb maybe needing a bit of that since it's not built-in in the tooling, just in a recoder view or just in conversations among devs. JOËL: [inaudible 09:26] Beyond just the idea of wrapping your values and making sure you check them all the time, there are patterns that make that easier or more painful. And even in something like Elm, the compiler would yell at me would make sure I could not have a runtime error by forgetting to check for nullability. It did not prevent me from writing monstrosities of nested repeated conditionals checking if nil, if nil, if nil. That I had to figure out some sort of, like, higher-level patterns that play nicely with that kind of software. And I think these are things that people have to sort of encounter, feel the pain, feel the frustration, and then move into those better patterns after the fact. And sometimes that's not easy because it's not obvious why that's a valuable pattern to approach. STEPHANIE: Yeah, I agree completely. Speaking of following patterns and kind of arriving at maybe an ideal version of [chuckles], you know, what you'd like your code to do, you know, to build what you are looking to build [laughs]...this is my very poor attempt at a smooth transition that Joël [laughter] manages to be able to do [laughs] whenever we're trying to shift into the topic of the episode. Anyway, today, we were hoping to talk a little bit about this idea between being an idealistic programmer and a pragmatic programmer and the different journeys that we've each been on in arriving kind of how to balance the two. JOËL: Yeah, you know, I think neither of these are absolutes, right? It's a spectrum. You probably move around that spectrum from day to day, and then probably, like, more general trends over your career. But I'm curious, for you today, if you had to pick one of those labels, like, which sort of zone of the spectrum would you put yourself in? Do you think you're more idealistic or more pragmatic? STEPHANIE: I think I'm in a more of an idealistic zone right now. JOËL: Would you say you're kind of like middle trending idealistic or kind of, like, pretty far down the idealistic side? STEPHANIE: Middle trending idealistic. I like that way of describing it. I want to know where you are. And then I kind of wanted to try to take a step back and even define what that means for both of us. JOËL: Right, right. I think the way I'd probably describe myself is a recovering idealist. STEPHANIE: Oof. Yeah [laughs]. JOËL: I think there was a time where I was really idealistic. I really like knowing sort of underlying theory of software construction, broader patterns. By patterns here, I don't mean necessarily, like, you know, the Gang of Four, but just general sort of approaches that work well and using that to guide my work. But I've also been trending a lot more into the, like, pragmatic side of things in the past few years. STEPHANIE: So, could you kind of tell me a little bit about what does pragmatic mean for you and what does ideal mean for you? JOËL: So, I think the pragmatic side of me it's about delivering working software. If you're not shipping anything, you know, the most beautiful piece of art that you've created just warms your heart is useless. So, I think I'm sort of at the extreme end of pragmatism, right? It's all about shipping and shipping fast. And, in the end, that's generally the goal of software. On the more idealistic side, the sort of doing everything kind of perfect or by the book, or, you know, maybe in a way that brings you personal satisfaction, oftentimes, at the expense of shipping and vice versa. Sometimes shipping comes at the expense of writing absolutely terrible code, but, of course, you know, there's value in both. Shipping is what actually delivers value to your users, your company, yourself if you're using the software. But if you're not following patterns and things, you're often stuck in a really short-term thinking loop, where you are maybe delivering value today at the cost of being able to deliver value tomorrow or writing code that is unreadable or code that is difficult to collaborate on. So, more than just me shipping an individual feature, I've got to think about, while I'm working with a team, how can I help them be able to ship features or build on top of my work for tomorrow? So, that's sort of how I visualize the field. I'm curious what the words idealism and pragmatism mean to you. STEPHANIE: Yeah. I agree with you that pragmatism is, you know, this idea of delivering working software. And I think I have seen it very, you know, kind of condensed as, like, moving quickly, getting stuff out the door, basically, like, end result being, like, a thing that you can use, right? I think I've personally been reassessing that idea a lot because I'm kind of almost wondering like, well, what are we moving quickly for [laughs]? I sometimes have seen pragmatism just end there being like, okay, like, it's all about velocity. And then, I'm kind of stuck being like, well, if you write working software for, you know, completely the wrong thing, is that still pragmatic? I don't know. So, that's kind of where I'm at these days with–I'm feeling a little bit more suspect of pragmatism, at least wanting to make sure that, especially with the people that I'm working with day to day, that we're agreeing on what that means and what success means. And then, as for idealism, I think also, actually, I now have a little bit of duality in terms of how I understand that as well. One of them being, yes, definitely, like, by the book or, like, by the ideas that we've, you know, some very smart people [laughs] have figured out as, like, this is clean or good quality, or these are the patterns to, you know, make your code as, again, as clean, I don't know, kind of putting air quotes around that, as possible. And then, I actually like what you really said about code that warms your heart [laughs] that you feel, like, really moved by or, like, just excited about or inspired by because I think that can also be a little bit different from just following theories that other people have defined. The more I spend doing this stuff, the more I am convinced that writing software is actually a very creative practice. And that's something that I've, like, definitely had to balance with the pragmatism a bit more because there are days when it's just not coming [chuckles], you know, like, I just stare at a blank, new file. And I'm like, I can't even imagine what these classes would be because, like, that creative part of my brain just, like, isn't on that day. So, that's kind of where I'm sitting in terms of, like, what idealistic programming kind of seems to me. JOËL: There's definitely an element of programming that feels like self-expression, you know, there are parameters around that. And working with a team, you probably all sort of, like, move towards some average. But I would definitely say that there is some element of self-expression in coding. STEPHANIE: Yeah, 100%. Have you heard about this paper called Programming as Theory Building? JOËL: The name sounds vaguely familiar, but I can't place the main idea in my mind right now. STEPHANIE: It's, like, an academic-ish paper from the 80s. And I'll link to it in the show notes because I can't remember the author right now. But the idea is writing code is actually just one way of expressing a theory that we are building. In fact, that expression doesn't even....it's like, it's impossible for it to fully encapsulate everything that was involved in the building of the theory because every decision you make, you know, you decide what not to do as well, right? Like, all the things that you didn't encode in your application is still part of this theory, like stuff that you rejected in order to interpret and make abstract the things that you are translating from the quote, unquote "real world" into code. That really stuck with me because, in that sense, I love this idea that you can create your own little world, right? Like, you're developing it when you code. And that is something that gets lost a little bit when we're just focused on the pragmatic side of things. JOËL: Where things get tricky as well is that when you're working with a team, you're not just building your own little world. You're building a shared world with shared mental models, shared metaphors. That's where oftentimes it becomes important to make sure that the things that you are thinking about are expressed in a way that other people could read your code and then immediately pick up on what's happening. And that can be through things like documentation, code comments. It can also be through more rigorous data modeling. So, for example, I am a huge fan of value objects in general. I tend to not have raw numbers floating around in an app. I like to wrap them in some kind of class and say, "Hey, these numbers that are floating around they actually represent a thing," and I'll name that thing so that other people can get a sense that, oh, it is one of the moving parts of this app, and then here are the behaviors that we expect on it. And that is partly for sort of code correctness and things like that but also as a sort of way of communicating and a way of contributing to that shared reality that we're creating with the team in a way that if I just left a raw number, that would be almost, like, leaving something slightly undefined. Like, the number is there. It does a thing, but what it does is maybe a little bit more implied. I know in my mind that this is a dollar amount, and maybe there's even a comment above it that says, "Dollar amount." But it makes it a little bit harder for it to play in with everybody else's realities or view of the system than if it were its own object. STEPHANIE: Yeah, I like what you said about you're building a shared world with your fellow colleagues. And that helped explain to me why, as some people say, naming is the hardest part about building software because, yeah, like you said, even just saying you are wanting to make a method or class expressive. And we talked about how code is a way of expressing yourself. You could, like, name all your stuff in Wingdings [laughs], but we don't. I actually don't know if you could do that. But that was, for some reason, what I imagined. I was like, it's possible, and you could deliver software in complete gibberish [laughs]. JOËL: In theory, could you say that naming your variables as emoji is the most expressive way? Because now it's all emotions. STEPHANIE: A picture is worth a thousand words, as they say. JOËL: So, this variable is the frowny face, upside-down smile face. It doesn't get more expressive than that. STEPHANIE: At a former company, in our Slack workspace, I had a co-worker who loved to use the circus tent emoji to react to things. And, like, I'm convinced that no one really knew what it meant, but we also kind of knew what it meant. We were just like, oh yeah, that's the emoji that she uses to express amusement or, like, something a little bit ironic. And we all kind of figured it out [laughs] eventually. So, again, I do think it's possible. I bet someone has done, like, a creative experiment with writing an application in just emojis. This is now going to be some research I do after this episode [laughter]. JOËL: It is fun when you have, like, a teammate. You know they have the signature emoji that they respond to on things. STEPHANIE: Yep. Absolutely. So, you know, we kind of spent a little bit of time talking about idealism. I actually wanted to pull back to the idea of pragmatism because, in preparation for this episode, I also revisited my copy of The Pragmatic Programmer. Are you familiar with this book? Have you read it at all? JOËL: I have read it. It's been probably ten years. We did, I think, a book club at thoughtbot to go through the book. STEPHANIE: I was skimming the table of contents because I was curious about, again, that, like, definition of pragmatism. You and I had kind of talked about how it can be short-sighted. But what I was actually pretty impressed with, and I imagine this is why the book holds up, you know, after decades, is success for them also means being able to continue to deliver quality software. And that idea of continuity kind of implied, to me, that there was an aspect of, like, making sure the quality meets a certain threshold and, like, incorporating these theories and doing the best practices because they're thinking about success over time, right? Not just the success of this particular piece that you're delivering. JOËL: I would say most people in our industry are sort of balancing those two objectives, right? They're like, we want to have a decent velocity and ship things, but at the same time, we want to be able to keep delivering. We want a certain threshold of quality. In between those two objectives, there is a sea of trade-offs, and how you manage them are probably a little bit part of your personality as a developer and is probably also, to a certain extent, a function of your experience, learning sort of when to lean more into taking some shortcuts to ship faster and when to double down on certain practices that increase code quality, and what aspects of quality value more than others because not all forms of quote, unquote, "quality" are the same. I think a sort of source of danger, especially for newer developers, is you sort of start on almost, like, a hyper-pragmatic side of things because most people get into software because they want to build things. And the ultimate way to build is to ship, and then you sort of encounter problems where you realize, oh, this code is really clunky. It's harder and harder to ship. Let me learn some elements of code quality. Let's get better at my craft so that I can build software that has fewer bugs or that I can ship more consistently. And that's great. And then, you sort of run into some, like, broader sort of theories of programming: patterns, structures, things like that. And it becomes very easy to sort of blindly copy-paste that everywhere to the point where I think it's almost a bit of a meme, the, like, intermediate programmer who's read Clean Code or the Design Patterns book and is just now, like, applying these things blindly to every piece of code they encounter to the annoyance of the entire team. STEPHANIE: I think you just about described my trajectory [laughter], though hopefully, I was not so obnoxious about [laughs] it for my team having to deal with my, like, discovering [laughs] theories that have long been used. JOËL: I think we kind of all go through that journey to a certain extent, right? It's a little bit different for every one of us, but I think this is a journey that is really common for developers. STEPHANIE: Yeah. One thing I frequently think about a lot is how much I wished I had known some of that theory earlier. But I don't think I have an answer one way or another. It's like; I'm not sure if having that knowledge earlier really would have helped me because I've also definitely been in...I'm just thinking about, like, when I was in college in lectures trying to absorb theories that made no sense to me because I had no, like, practical experience to connect it to. It's almost, like, maybe there is, like, that perfect time [laughs] where it is the most valuable for what you're doing. And I don't know. I kind of believe that there is a way to bridge that gap. JOËL: I mean, now we're kind of getting into an element of pedagogy. Do you sort of teach the theory first, and then show how to apply it to problems? Or do you show problems and then introduce bits of theory to help people get unstuck and maybe then cap it off by like, oh, these, like, five different, like, techniques I showed you to, like, solve five different problems, turns out they all fit in some grand unified theory? And, like, here's how the five things you thought were five different techniques are actually the same technique viewed from five different perspectives. Let me blow your mind. STEPHANIE: That's a Joël approach [laughter] to teaching if I've ever heard one. JOËL: I'm a huge fan of that approach. Going back to some of the, like, the functional programming ideas, I think that's one that really connected for me. I struggled to learn things like monads, and functors, and things like that. And I think, in my mind, these two approaches is like the Haskell school of teaching and the Elm school of teaching. Haskell will sort of say, "Hey, let me teach you about this theory of monads and all these things, and then, we'll look at some ways where that can be applied practically." Whereas Elm will say, "No, you don't need to know about this. Let's look at some practical problems. Oh, you've got null values you need to check. Here's how you can, like, handle nullability in a safe way. Oh, you've got a bunch of HTTP requests that might resolve in random order, and you want to, like, deal with them when they all come back. Here's some tips on how you can do that." And then, you have three or four things, and then, eventually, it just sort of lets you say, "Wait a minute, all of these problems are sort of all the same, and it turns out they all fit in some unified theory." And then, the light bulb goes off, and you're like, "Ooh, so now when I'm dealing with unknown blobs of Jason trying to parse data out of them, I'll bet I can use the same techniques I used for chaining HTTP requests to dig multiple dependent pieces of JSON." STEPHANIE: Yeah. And that's so satisfying, right? It really is kind of leveling up in that Galaxy Brain meme sort of way. JOËL: Yeah. And that's maybe to a certain extent even a value of idealism because if you build your system in such a way that it follows some of these patterns, then insights and intuitions that people have in one part of your code can then carry to other parts of your code, and that's incredibly powerful. STEPHANIE: Yeah. And I almost wonder because you also mentioned kind of where you end up on the spectrum is a function of your experience. I wonder if us, you know, being consultants and seeing patterns across many applications also kind of contributes to the striving for idealism [laughs]. JOËL: It's kind of both, right? Because there's very high incentive to ship pretty rapidly, especially if you're on a shorter engagement or if you're on a project that has a shorter timescale. But also, yes, because you've seen so many projects, you've seen how things can go wrong. Also, you've seen the same problem from 20 different perspectives that are all slightly different. And so, some of those broader patterns can start emerging in your head. STEPHANIE: Yeah, honestly, I think that's kind of the work that I enjoy the most in consulting because a lot of clients bring us on when they're like, "Hey, like, we've reached a point where our velocity has slowed down. Like, can you help us unstick our developers?" And that's actually when I've found that leaning on the theories and maybe a little bit of idealism is actually really useful because I'm kind of providing those tools to developers at this time when they need it. That's kind of why I have been saying trending idealism because I have found that particularly useful at work. JOËL: There's an element here of, like, looking at a bunch of different use cases and then finding some sort of unifying model or theory. And that's a word that I think programmers have a love-hate relationship with: Abstraction. I don't know about you, but designing abstractions is a lot of fun for me. I love designing abstractions. I have always loved designing abstractions. It's not always the best use of my time, and it's not always the best thing for a codebase. STEPHANIE: Ooh, okay, okay. This was a good transition. I hear you that, like, yeah, love-hate relationship. It's hard. That's kind of where I've ended up. It's really hard. And I think it's because it requires that creative thinking. JOËL: It requires that creative thinking. And then also, like, it requires you to sort of see more broadly, a more broad picture. What are the things that are connected, the things that are disconnected, even though they seem related? And, like, being able to sort of slice those similarities from each other. STEPHANIE: Yeah. I agree. And the interesting part is that, like, a lot of the time you just don't know yet. And you kind of have to come back to reality and admit that you don't know yet, you know, got to come back to earth, take a look around, and, yeah, you can go through the thought exercise of thinking [laughs] about all of the possibilities, and I imagine you could do that forever [laughs]. JOËL: I mean, that's why we have heuristics like the rule of three that says, "Don't abstract something out or attempt to DRY code until you've seen three use cases of it." So, maybe leave a little bit of duplication or a little bit of maybe not perfectly factored code until you have a couple of more examples. And the sort of real picture starts emerging a little bit more. STEPHANIE: So, I think we are kind of at this topic already, but was there a moment or was there something that kind of helped you realize, like, oh, I can't be in that space of imagining abstractions [laughs] forever when I have to deliver software? Like, what changed for you to be the, as you said yourself, recovering idealist and having to maybe employ some more pragmatic heuristics? JOËL: And I think, for me, it's partly being a consultant and being in a lot of projects and having that pressure to work with deadlines and sort of not having an infinite canvas to paint with, having to sort of fit some of my grand ideas into the reality of, we've got a week or two weeks to get this thing done, and also working with a team, and some ideas don't work well with every team. Every team is kind of at a different place. And abstractions sort of only serve you as well as they are useful to not only you but the team at large. So, if a team is not comfortable with a set of abstractions, or it's sort of, like, too far down a path, then that can be really challenging. And that's where something like the dry-rb set of gems, which has some really fun abstractions like a mental model for doing things, depending on the team, that can be a really heavy lift. And so, as much as I like those patterns, I might think long and hard before I try to push this on a whole team. STEPHANIE: Yeah, I kind of had to navigate a situation like that recently, where I was doing a code review, and I had left some suggestions about refactoring to encapsulate some responsibilities better. And then, I was like, oh, and then I noticed another thing that we could do to make that easier. And it, you know, definitely can start to spiral. And the author, you know, kind of responded to me and said, "Hey, like, I really appreciate these comments, but we are a bit tight on deadline for this project. So, is it okay if I, like, revisit this when we've delivered it?" And, you know, I was just like, "Yeah, it's totally up to you." At the end of the day, I want whoever's authoring this code to have, like, full agency about how they want to move forward. And it was really helpful for me to get that context of, like, oh, they're a bit tight on the deadline because then I can start to meet them where they're at. And maybe I can give some suggestions for moving towards that ideal state, but ones that are lower left, and that is still better than nothing. JOËL: That sounds awfully pragmatic. STEPHANIE: [laughs] JOËL: Moving in a positive direction, we're getting halfway. It's better than nothing. That's very pragmatic. STEPHANIE: Hmm. Wow. But it's pragmatically moving towards idealism. JOËL: [laughs] STEPHANIE: If that is even possible [laughs]. JOËL: Uh-huh. STEPHANIE: That's maybe the book that I'm going to write, not The Pragmatic Programmer, but The Pragmatically Idealistic Programmer [laughs]. JOËL: The Pragmatic Idealist. STEPHANIE: Ooh, yeah, I like that. Okay. Watch out for that book coming 2030 [laughter], written by me and Joël. JOËL: So, I think you brought up a really interesting point, which is the idea of pragmatism versus idealism when it comes to code review. Do you find that you think about these ideas differently when reviewing somebody else's code versus when you write your own? STEPHANIE: Oooh, yeah. I'm not sure exactly why, but definitely, when I'm reviewing someone else's code, I'm already in the headspace of, you know, I have some separation, right? Like, I'm not in the mode of thinking very hard [laughs] about what I'm creating. I'm just, like, in the editing kind of phase. And then, I can actually pull more from different theories and ideas, and I find that actually quite easier. When I'm writing my own code, it's just whatever comes out, right? And then, hopefully, I have the time to revisit it and give it a scan, and then start to integrate the, like, idealistic theories and the patterns that I would like to be using. But it definitely...for patterns that I feel a lot more confident about or more familiar with, they just come out mostly kind of oriented in that way if I have the time, or sometimes I will make the time, you know. I'll just say, "It's not done yet," because I know it can be better. I think that could be another, like, pragmatically idealist way of handling that. JOËL: [laughs] STEPHANIE: Right? It's just telling people, "I'm not done." [laughs] It's not done until I do at least give it an attempt. JOËL: So, it's kind of a two-phase thing when you're writing your own code, whereas it's only a single phase when you're reviewing somebody else's. STEPHANIE: Yeah. Yeah. But, like I said earlier, it's like, I also really believe that I don't want to impose any of my ideas [laughs] onto others. I really believe that people have to arrive at it on their own. So, it used to bother me a little bit more when I was just like, oh, but this way is better [laughs]. When people wouldn't get on board, I would be sad about it. But as long as I know that I, like, left that comment, then I can give myself a pat on the back for trying to move towards that ideal state. What about you [laughs]? JOËL: I think this is probably also where I'm, like, now a recovering idealist. There was a time where I would leave a ton of comments on someone's PR. I almost had a view of like, how can I help you get your PR to be the best it can possibly be? And sometimes, if you start with something that's very rough around the edges, you're leaving a lot of comments. And I've been that guy who's left 50 comments on a PR. In retrospect, I think that was not being a good teammate. STEPHANIE: Hmm. JOËL: So, I think maybe my mental model or my, like, goal for PR review has changed a little bit. It's less about how can I help you make your code the best it can possibly be? And a how can I help you get your code to mergeable? And it's possible that mergeable means best that it can possibly be, but that's usually not the case. So, I'm going to give you some feedback: some things that confuse me, maybe raise one or two patterns that are existing in the app that maybe you weren't aware of that you should maybe consider applying. Maybe I'll raise a couple of ideas that are new, but that apply here. And those might just be a, "Hey, let's just think about this. Maybe we don't want to do this in this PR, but maybe we want to look at them at some point. Or we should be thinking about this in a sort of rule of three situation. If we see this come up another time, maybe consider introducing a strategy pattern here, or maybe consider making this a value object, or separating these side effects from these pure behavior." But it's more of a dialogue about how can I help you get your PR to the point where it is mergeable? STEPHANIE: Yeah. Another thing I thought about just now is both are meaningful or, like, both can provide meaning in different ways, and people ascribe different amounts of meaning to both; where I had worked with someone, a client developer before, who was not super interested in doing any kind of refactoring or, like, any, you know, second passes for quality. Because, for him, like, he just wanted to ship, right? That was where he found meaning in his work. Whereas that actually made my work feel a lot more meaningless [chuckles] because I'm like, well, if we're just kind of hands on a keyboard, like robots shipping code, I don't know, that doesn't feel particularly motivating for me. You know, I do want to employ some of that craft a little bit more. JOËL: And, I guess, yeah, idealism versus pragmatism is also...it's a personal individual thing. There's an element where it's a team decision, or at least a sense of, like, how much quality do we need at this point in the life cycle of the project? And what are the areas where we particularly want to emphasize quality? What are our quality standards? And that's, to a certain extent, consensus among the team that it's individual members. And it's also coming from team leadership. STEPHANIE: Yeah. Yeah, exactly. I mentioned that, you know, just to, I think, shed a little bit of light that it's usually not personal, right [laughs]? There's that part of understanding that is really important to, yeah, like, keep building this shared world of writing software, and, hopefully, it should be meaningful for all of us. JOËL: I think a few takeaways that I have would be, one, the value of, like, theory and idealism. These things help you to become a better developer. They help you to spot patterns. It's probably good to sort of have in the background always be learning some new thing, whether that's learning a new set of patterns, or learning some mental models, thinking about, oh, the difference between side effects and pure code, learning about particular ways of structuring code. These are all things that are good to have in your back pocket to be able to apply to the code that you're doing, even if it's a sort of after-the-fact, hey, I've done a similar task three different times. Is there a broader principle? But then, also, take the time to really make sure that you're focusing on shipping code, and maybe that's learning to work in smaller chunks, working iteratively, learning to scope your work well. Because, in the end, delivering value is a thing that is something that we could all probably benefit from doing more of. And then, finally, taking some time to self-reflect, a little bit of self-awareness in this area. What are the aspects of pragmatism and idealism that you find personally meaningful? What are the elements that you think bring value to your work, to your team? And let that sort of guide you on your next code writing or PR review. STEPHANIE: On that note, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at: tbot.io/referral. Or you can email us at: referrals@thoughtbot.com with any questions.
Joël shares his recent project challenge with Tailwind CSS, where classes weren't generating as expected due to the dynamic nature of Tailwind's CSS generation and pruning. Stephanie introduces a personal productivity tool, a "thinking cap," to signal her thought process during meetings, which also serves as a physical boundary to separate work from personal life. The conversation shifts to testing methodologies within Rails applications, leading to an exploration of testing philosophies, including developers' assumptions about database cleanliness and their impact on writing tests. Avdi's classic post on how to use database cleaner (https://avdi.codes/configuring-database_cleaner-with-rails-rspec-capybara-and-selenium/) RSpec change matcher (https://rubydoc.info/gems/rspec-expectations/RSpec%2FMatchers:change) Command/Query separation (https://martinfowler.com/bliki/CommandQuerySeparation.html) When not to use factories (https://thoughtbot.com/blog/speed-up-tests-by-selectively-avoiding-factory-bot) Why Factories? (https://thoughtbot.com/blog/why-factories) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: I'm working on a new project, and this is a project that uses Tailwind CSS for its styling. And I ran into a bit of an annoying problem with it just getting started, where I was making changes and adding classes. And they were not changing the things I thought they would change in the UI. And so, I looked up the class in the documentation, and then I realized, oh, we're on an older version of the Tailwind Rails gem. So, maybe we're using...like, I'm looking at the most recent docs for Tailwind, but it's not relevant for the version I'm using. Turned out that was not the problem. Then I decided to use the Web Inspector and actually look at the element in my browser to see is it being overwritten somehow by something else? And the class is there in the element, but when I look at the CSS panel, it does not show up there at all or having any effects. And that got me scratching my head. And then, eventually, I figured it out, and it's a bit of a facepalm moment [laughs]. STEPHANIE: Oh, okay. JOËL: Because Tailwind has to, effectively, generate all of these, and it will sort of generate and prune the things you don't need and all of that. They're not all, like, statically present. And so, if I was using a class that no one else in the app had used yet, it hadn't gotten generated. And so, it's just not there. There's a class on the element, but there's no CSS definition tied to it, so the class does nothing. What you need to do is there's a rake task or some sort of task that you can run that will generate things. There's also, I believe, a watcher that you can run, some sort of, like, server that will auto-generate these for you in dev mode. I did not have that set up. So, I was not seeing that new class have any effect. Once I ran the task to generate things, sure enough, it worked. And Tailwind works exactly how the docs say they do. But that was a couple of hours of my life that I'm not getting back. STEPHANIE: Yeah, that's rough. Sorry to hear. I've also definitely gone down that route of like, oh, it's not in the docs. The docs are wrong. Like, do they even know what they're talking about? I'm going to fix this for everyone. And similarly have been humbled by a facepalm solution when I'm like, oh, did I yarn [laughs]? No, I didn't [laughs]. JOËL: Uh-huh. I'm curious, for you, when you have sort of moments where it's like the library is not behaving the way you think it is, is your default to blame yourself, or is it to blame the library? STEPHANIE: [laughs]. Oh, good question. JOËL: And the follow-up to that is, are you generally correct? STEPHANIE: Yeah. Yep, yep, yep. Hmm, I will say I externalize the blame, but I will try to at least do, like, the basic troubleshooting steps of restarting my server [laughter], and then if...that's as far as I'll go. And then, I'll be like, oh, like, something must be wrong, you know, with this library, and I turn to Google. And if I'm not finding any fruitful results, again, you know, one path could be, oh, maybe I'm not Googling correctly, but the other path could be, maybe I've discovered something that no one else has before. But to your follow-up question, I'm almost, like, always wrong [laughter]. I'm still waiting for the day when I, like, discover something that is an actual real problem, and I can go and open an issue [chuckles] and, hopefully, be validated by the library author. JOËL: I think part of what I heard is that your debugging strategy is basic, but it's not as basic as Joël's because you remember to restart the server [chuckles]. STEPHANIE: We all have our days [laughter]. JOËL: Next time. So, Stephanie, what is new in your world? STEPHANIE: I'm very excited to share this with you. And I recognize that this is an audio medium, so I will also describe the thing I'm about to show you [laughs]. JOËL: Oh, this is an object. STEPHANIE: It is an object. I got a hat [laughs]. JOËL: Okay. STEPHANIE: I'm going to put it on now. It's a cap that says "Thinking" on it [laughs] in, like, you know, fun sans serif font with a little bit of edge because the thinking is kind of slanted. So, it is designy, if you will. It's my thinking cap. And I've been wearing it at work all week, and I love it. As a person who, in meetings and, you know, when I talk to people, I have to process before I respond a lot of the time, but that has been interpreted as, you know, maybe me not having anything to say or, you know, people aren't sure if I'm, you know, still thinking or if it's time to move on. And sometimes I [chuckles], you know, take a long time. My brain is just spinning. I think another funny hat design would be, like, the beach ball, macOS beach ball. JOËL: That would be hilarious. STEPHANIE: Yeah. Maybe I need to, like, stitch that on the back of this thinking cap. Anyway, I've been wearing it at work in meetings. And then, when I'm just silently processing, I'll just point to my hat and signal to everyone what's [laughs] going on. And it's also been really great for the end of my work day because then I take off the hat, and because I've taken it off, that's, like, my signal, you know, I have this physical totem that, like, now I'm done thinking about work, and that has been working. JOËL: Oh, I love that. STEPHANIE: Yeah, that's been working surprisingly well to kind of create a bit more of a boundary to separate work thoughts and life thoughts. JOËL: Because you are working from home and so that boundary between professional life and personal life can get a little bit blurry. STEPHANIE: Yeah. I will say I take it off and throw it on the floor kind of dramatically [laughter] at the end of my work day. So, that's what's new. It had a positive impact on my work-life balance. And yeah, if anyone else has the problem of people being confused about whether you're still thinking or not, recommend looking into a physical thinking cap. JOËL: So, you are speaking at RailsConf this spring in Detroit. Do you plan to bring the thinking cap to the conference? STEPHANIE: Oh yeah, absolutely. That's a great idea. If anyone else is going to RailsConf, find me in my thinking cap [laughs]. JOËL: So, this is how people can recognize Bikeshed co-host Stephanie Minn. See someone walking around with a thinking cap. STEPHANIE: Ooh. thinkingbot? JOËL: Ooh. STEPHANIE: Have I just designed new thoughtbot swag [laughter]? We'll see if this catches on. JOËL: So, we were talking recently, and you'd mentioned that you were facing some really interesting dilemmas when it came to writing tests and particularly how tests interact with your test database. STEPHANIE: Yeah. So, I recently, a few weeks ago, joined a new client project and, you know, one of the first things that I do is start to run those tests [laughs] in their codebase to get a sense of what's what. And I noticed that they were taking quite a long time to get set up before I even saw any progress in terms of successes or failures. So, I was kind of curious what was going on before the examples were even run. And when I tailed the logs for the tests, I noticed that every time that you were running the test suite, it would truncate all of the tables in the test database. And that was a surprise to me because that's not a thing that I had really seen before. And so, basically, what happens is all of the data in the test database gets deleted using this truncation strategy. And this is one way of ensuring a clean slate when you run your tests. JOËL: Was this happening once at the beginning of the test suite or before every test? STEPHANIE: It was good that it was only running once before the test suite, but since, you know, in my local development, I'm running, like, a file at a time or sometimes even just targeting a specific line, this would happen on every run in that situation and was just adding a little bit of extra time to that feedback loop in terms of just making sure your code was working if that's part of your workflow. JOËL: Do you know what version of Rails this project was in? Because I know this was popular in some older versions of Rails as a strategy. STEPHANIE: Yeah. So, it is Rails 7 now, recently upgraded to Rails 7. It was on Rails 6 for a little while. JOËL: Very nice. I want to say that truncation is generally not necessary as of Rails...I forget if it's 5 or 6. But back in the day, specifically for what are now called system tests, the sort of, like, Capybara UI-driven browser tests, you had, effectively, like, two threads that were trying to access the database. And so, you couldn't have your test data wrapped in a transaction the way you would for unit tests because then the UI thread would not have access to the data that had been created in a transaction just for the test thread. And so, people would use tools like Database Cleaner to use a truncation strategy to clear out everything between tests to allow a sort of clean slate for these UI-driven feature specs. And then, I want to say it's Rails 5, it may have been Rails 6 when system tests were added. And one of the big things there was that they now could, like, share data in a transaction instead of having to do two separate threads and one didn't have access to it. And all of a sudden, now you could go back to transactional fixtures the way that you could with unit tests and really take advantage of something that's really nice and built into Rails. STEPHANIE: That's cool. I didn't know that about system tests and that kind of shift happening. I do think that, in this case, it was one of those situations where, in the past, the database truncation, in this case, particular using the Database Cleaner gem was necessary, and that just never got reassessed as the years went by. JOËL: That's one of the classic things, right? When you upgrade a Rails app over multiple versions, and sometimes you sort of get a new feature that comes in for free with the new version, and you might not be aware of it. And some of the patterns in the app just kind of keep going. And you don't realize, hey, this part of the app could actually be modernized. STEPHANIE: So, another interesting thing about this testing situation is that I learned that, you know, if you ran these tests, you would experience this truncation strategy. But the engineering team had also kind of played around with having a different test setup that didn't clean the database at all unless you opted into it. JOËL: So, your test database would just...each test would just keep writing to the database, but they're not wrapped in transactions. Or they are wrapped in transactions, but you may or may not have some additional data. STEPHANIE: The latter. So, I think they were also using the transaction strategy there. But, you know, there are some reasons that you would still have some data persisted across test runs. I had actually learned that the use transactional fixtures config for RSpec doesn't roll back any data that might have been created in a before context hook. JOËL: Yep, or a before all. Yeah, the transaction wraps the actual example, but not anything that happens outside of it. STEPHANIE: Yeah, I thought that was an interesting little gotcha. So, you know, now we had these, like, two different ways to run tests. And I was chatting with a client developer about how that came to be. And we then got into an interesting conversation about, like, whether or not we each expect a clean database in the first place when we write our tests or when we run our tests, and that was an area that we disagreed. And that was cool because I had not really, like, thought about like, oh, how did I even arrive at this assumption that my database would always be clean? I think it was just, you know, from experience having only worked in Rails apps of a certain age that really got onto the Database [laughs] Cleaner train. But it was interesting because I think that is a really big assumption to make that shapes how you then approach writing tests. JOËL: And there's kind of a couple of variations on that. I think the sort of base camp approach of writing Rails with fixtures, you just sort of have, for the most part, an existing set of data that's there that you maybe layer on a few extra things on. But there's base level; you just expect a bunch of data to exist in your test database. So, it's almost going off the opposite assumption, where you can always assume that certain things are already there. Then there's the other extreme of, like, you always assume that it's empty. And it sounds like maybe there's a position in the middle of, like, you never know. There may be something. There may not be something, you know, spin the wheel. STEPHANIE: Yeah. I guess I was surprised that it, you know, that was just a question that I never really asked myself prior to this conversation, but it could feel like different testing philosophies. But yeah, I was very interested in this, you know, kind of opinion that was a little bit different from mine about if you assume that your database, your test database, is not clean, that kind of perhaps nudges you in the direction of writing tests that are less coupled to the database if they don't need to be. JOËL: What does coupling to the database mean in this situation? STEPHANIE: So, I'm thinking about Rails tests that might be asserting on a change in database behavior, so the change matcher in RSpec is one that I see maybe sometimes used when it doesn't need to be used. And we're expecting, like, account to have changed the count of the number of records on it for a model have changed after doing some work, right? JOËL: And the change matcher from RSpec is one that allows you to not care whether there are existing records or not. It sort of insulates you from that. STEPHANIE: That's true. Though I guess I was thinking almost like, what if there was some return value to assert on instead? And would that kind of help you separate some side effects from methods that might be doing too much? And kind of when I start to see tests that have both or are asserting on something being returned, and then also something happening, that's one way of, like, figuring out what kind of coupling is going on inside this test. JOËL: It's the classic command-query separation principle from object-oriented design. STEPHANIE: I think another one that came to mind, another example, especially when you're talking about system tests, is when you might be using Capybara and you end up...maybe you're going through a flow that creates a record. But from the user perspective, they don't actually know what's going on at the database level. But you could assert that something was created, right? But it might be more realistic at that level of abstraction to be asserting some kind of visual element that had happened as a result of the flow that you're testing. JOËL: Yeah. I would, in fact, go so far as to say that asserting on the state of your database in a system test is an anti-pattern. System tests are sort of, by design, meant to be all about user behavior trying to mimic the experience of a user. And a user of a website is not going to be able to...you hope they're not able to SSH into [chuckles] your database and check the records that have been created. If they can, you've got another problem. STEPHANIE: I wonder if you could take this idea to the extreme, though. And do you think there is a world where you don't really test database-level concerns at all if you kind of believe this idea that it doesn't really matter what the state of it should be? JOËL: I guess there's a few different things on, like, what it matters about the state of it because you are asserting on its state sort of indirectly in a sort of higher level integration test. You're asserting that you see certain things show up on the screen in a system test. And maybe you want to say, "I do certain tasks, and then I expect to see three items in an unordered list." Those three items probably come from the database, although, you know, you could have it where they come from an API or something like that. So, the database is an implementation level. But if you had random data in your database, you might, in some tests, have four items in the list, some tests have five. And that's just going to be a flaky test, and that's going to be incredibly painful. So, while you're not asserting on the database, having control over it during sort of test setup, I think, does impact the way you assert. STEPHANIE: Yeah, that makes sense. I was suddenly just thinking about, like, how that exercise can actually tell you perhaps, like, when it is important to, in your test setup, be persisting real records as opposed to how much you can get away with, like, not interacting with it because, like, you aren't testing at that integration level. JOËL: That brings up a good point because a lot of tests probably you might need models, but you might not need persisted models to interact with them, if you're testing a method on a model that just does things based off its internal state and not any of the ActiveRecord database queries, or if you have some other service or something that consumes a model that doesn't necessarily need to query. There's a classic blog post on the thoughtbot blog about when you should not reuse. There's a classic blog post on the thoughtbot blog about when not to use FactoryBot. And, you know, we are the makers of FactoryBot. It helps set up records in your database for testing. And people love to use it all the time. And we wrote an article about why, in many cases, you don't need to create something into the database. All you need is just something in memory, and that's going to be much faster than using FactoryBot because talking to the database is expensive. STEPHANIE: Yeah, and I think we can see that in the shift from even, like, fixtures to factories as well, where test data was only persisted as needed and as needed in individual tests, rather than seeding it and having all of those records your entire test run. And it's cool to see that continuing, you know, that idea further of like, okay, now we have this new, popular tool that reduce some of that. But also, in most cases, we still don't need...it's still too much. JOËL: And from a performance perspective, it's a bit of a see-saw in that fixtures are a lot faster because they get inserted once at the beginning of your test run. So, a SQL execution at the beginning of a test run and then every test after that is just doing its thing: maybe creating a record inside of a transaction, maybe not creating any records at all. And so, it can be a lot faster as opposed to using FactoryBot where you're creating records one at a time. Every create call in a test is a round trip to the database, and those are expensive. So, FactoryBot tests tend to be more expensive than those that rely on fixtures. But you have the advantage of more control over what data is present and sort of more locality because you can see what has been created at the test level. But then, if you decide, hey, this is a test where I can just create records in memory, that's probably the best of all worlds in that you don't need anything created ahead with fixtures. You also don't need anything to be inserted using FactoryBot because you don't even need the database for this test. STEPHANIE: I'm curious, is that the assumption that you start with, that you don't need a persisted object when you're writing a basic unit test? JOËL: I think I will as much as possible try not to need to persist and only if necessary use persist records. There are strategies with FactoryBot that will allow you to also, like, build stubbed or just build in memory. So, there's a few different variations that will, like, partially do things for you. But oftentimes, you can just new up an object, and that's what I will often start with. In many cases, I will already know what I'm trying to do. And so, I might not go through the steps of, oh, new up an object. Oh no, I'm getting a I can't do the thing I need to do. Now, I need to write to the database. So, if I'm testing, let's say, an ActiveRecord scope that's filtering down a series of records, I know that's a wrapper around a database query. I'm not going to start by newing up some records and then sort of accidentally discovering, oh yeah, it does write to the database because that was pretty clear to me from the beginning. STEPHANIE: Yeah. Like, you have your mental shortcuts that you do. I guess I asked that question because I wonder if that is a good heuristic to share with maybe developers who are trying to figure out, like, should they create persisted records or, you know, use just regular instance in memory or, I don't know, even [laughs] use, like, a double [laughs]? JOËL: Yeah, I've done that quite a bit as well. I would say maybe my heuristic is, is the method under test going to need to talk to the database? And, you know, I may or may not know that upfront because if I'm test driving, I'm writing the test first. So, sometimes, maybe I don't know, and I'll start with something in memory and then realize, oh, you know, I do need to talk to the database for this. And this is for unit tests, in particular. For something more like an integration test or a system test that might require data in the database, system tests almost always do. You're not interacting with instances in memory when you're writing a system test, right? You're saying, "Given the database state is this when I visit this URL and do these things, this page reacts in such and such a way." So, system tests always write to the database to start with. So, maybe that's my heuristic there. But for unit tests, maybe think a little bit about does your method actually need to talk to the database? And maybe even almost give yourself a challenge. Can I get away with not talking to the database here? STEPHANIE: Yeah, I like that because I've certainly seen a lot of unit tests that are integration tests in disguise [laughs]. JOËL: Isn't that the truth? So, we kind of opened up this conversation with the idea of there are different ways to manage your database in terms of, do you clean or not clean before a test run? Where did you end up on this particular project? STEPHANIE: So, I ended up with a currently open PR to remove the need to truncate the database on each run of the test suite and just stick with the transaction for each example strategy. And I do think that this will work for us as long as we decide we don't want to introduce something like fixtures, even though that is actually also a discussion that's still in the works. But I'm hoping with this change, like, right now, I can help people start running faster tests [chuckles]. And should we ever introduce fixtures down the line, then we can revisit that. But it's one of those things that I think we've been living with this for too long [laughs]. And no one ever questioned, like, "Oh, why are we doing this?" Or, you know, maybe that was a need, however many years ago, that just got overlooked. And as a person new to the project, I saw it, and now I'm doing something about it [laughs]. JOËL: I love that new person energy on a project and like, "Hey, we've got this config thing. Did you know that we didn't need this as of Rails 6?" And they're like, "Oh, I didn't even realize that." And then you add that, and it just moves you into the future a little bit. So, if I understand the proposed change, then you're removing the truncation strategy, but you're still going to be in a situation where you have a clean database before each test because you're wrapping tests in transactions, which I think is the default Rails behavior. STEPHANIE: Yeah, that's where we're at right now. So, yeah, I'm not sure, like, how things came to be this way, but it seemed obvious to me that we were kind of doing this whole extra step that wasn't really necessary, at least at this point in time. Because, at least to my knowledge [laughs], there's no data being seeded in any other place. JOËL: It's interesting, right? When you have a situation where this was sort of a very popular practice for a long time, a lot of guides mentioned that. And so, even though Rails has made changes that mean that this is no longer necessary, there's still a long tail of apps that will still have this that may be upgraded later, and then didn't drop this, or maybe even new apps that got created but didn't quite realize that the guide they were following was outdated, or that a best practice that was in their head was also outdated. And so, you have a lot of apps that will still have these sort of, like, relics of the past. And you're like, "Oh yeah, that's how we used to do things." STEPHANIE: So yeah, thanks, Joël, for going on this journey with me in terms of, you know, reassessing my assumptions about test databases. I'm wondering, like, if this is common, how other people, you know, approach what they expect from the test database, whether it be totally clean or have, you know, any required data for common flows and use cases of your system. But it does seem that little in between of, like, maybe it is using transactions to reset for each example, but then there's also some persistence that's happening somewhere else that could be a little tricky to manage. JOËL: On that note, shall we wrap up? STEPHANIE: Let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeeeeeee!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at: tbot.io/referral. Or you can email us at: referrals@thoughtbot.com with any questions.
Stephanie introduces her ideal setup for enjoying coffee on a bike ride. Joël describes his afternoon tea ritual. Exciting news from the hosts: both have been accepted to speak at RailsConf! Stephanie's presentation, titled "So, Writing Tests Feels Painful. What now?" aims to tackle the issues developers encounter with testing while offering actionable advice to ease these pains. Joël's session will focus on utilizing Turbo to create a Dungeons & Dragons character sheet, combining his passion for gaming with technical expertise. Their conversation shifts to artificial intelligence and its potential in code refactoring and other applications, such as enhancing the code review process and solving complex software development problems. Joël shares his venture into combinatorics, illustrating how this mathematical approach helped him efficiently refactor a database query by systematically exploring and testing all potential combinations of query segments. Transcript: JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. STEPHANIE: And I'm Stephanie Minn, and together, we're here to share a bit of what we've learned along the way. JOËL: So, Stephanie, what's new in your world? STEPHANIE: So, today I went out for a coffee on my bike, and I feel like I finally have my perfect, like, on-the-go coffee setup. We have this thoughtbot branded travel mug. So, it's one of the little bits of swag that we got from the company. It's, like, perfectly leak-proof. I'll link the brand in the show notes. But it's perfectly leak-proof, which is great. And on my bike, I have a little stem bag, so it's just, like, a tiny kind of, like, cylindrical bag that sits on the, like, vertical part of my handlebars that connects to the rest of my bag. And it's just, like, the perfect size for a 12-ounce coffee. And so, I put my little travel mug in there, and I just had a very refreshing morning. And I'd gone out on my bike for a little bit, stopping by for coffee and headed home to work. And I got to drink my coffee during my first meeting. So, it was a wonderful way to start the day. JOËL: Do you just show up at the coffee shop with your refillable mug and say, "Hey, can you pour some coffee in this?" STEPHANIE: Yeah. I think a lot of coffee places are really amenable to bringing your own travel mugs. So yeah, it's really nice because I get to use less plastic. And also, you know, when you get a to-go mug, it is not leak-proof, right? It could just slosh all over the place and spill, so not bike-friendly. But yeah, bring your own mug. It's very easy. JOËL: Excellent. STEPHANIE: So, Joël, what's new in your world? JOËL: Also, warm beverages. Who would have thought? It's almost like it's cold in North America or something. I've been really enjoying making myself tea in the afternoons recently. And I've been drinking this brand of tea that is a little bit extra. Every flavor of tea they have comes with a description of how the tea feels. STEPHANIE: Ooh. JOËL: I don't know who came up with these, but they're kind of funny. So, one that I particularly enjoy is described as feels like stargazing on an empty beach. STEPHANIE: Wow. That's very specific. JOËL: They also give you tasting notes. This one has tastes of candied violet, elderberry, blackberry, and incense. STEPHANIE: Ooh, that sounds lovely. Are you drinking, like, herbal tea in the afternoon, or do you drink caffeinated tea? JOËL: I'll do caffeinated tea. I limit myself to one pot of coffee that I brew in the morning, and then, whenever that's done, I switch to tea. Tea I allow myself anything: herbal, black tea; that's fine. STEPHANIE: Yeah, I can't have too much caffeine in the afternoon either. But I do love an extra tea. I wish I could remember, like, what even was in this tea or what brand it was, but once I had a tea that was a purplish color. But then, when you squeeze some lemon in it, or I guess maybe anything with a bit of acid, it would turn blue. JOËL: Oh, that's so cool. STEPHANIE: Yeah, I'll have to find what this tea was [laughs] and update the podcast for any tea lovers out there. But yeah, it was just, like, a little bit of extra whimsy to your regular routine. JOËL: I love adding a little whimsy to my day, even if it's just seeing a random animated GIF that a coworker has sent or Tuple has some of the, like, reactions you can send if you're pairing with someone. And I don't use those very often, so whenever one of those comes through, and it's like, ship it or yay, that makes me very happy. STEPHANIE: Agreed. JOËL: This week is really fun because as we were prepping for this episode, we both realized that there is a lot that's been new in our world recently. And Stephanie, in particular, you've got some pretty big news that recently happened to you. STEPHANIE: Yeah, it turns out we're making the what's new in your world segment the entire episode today [laughs]. But my news is that I am speaking at RailsConf this year, so that is May 7th through 9th in Detroit. And so, yeah, I haven't spoken at a RailsConf before, only a RubyConf. So, I'm looking forward to it. My talk is called: So, Writing Tests Feels Painful. What now? JOËL: Wait, is writing tests ever painful [laughs]? STEPHANIE: Maybe not for you, but for the rest of us [laughs]. JOËL: No, it absolutely is. I, right before this recording, came from a pairing session where we were scratching our heads on an, like, awkward-to-write test. It happens to all of us. STEPHANIE: Yeah. So, I was brainstorming topics, and I kind of realized, especially with a lot of our consulting experience, you know, we hear from developers or even maybe, like, engineering managers a lot of themes around like, "Oh, like, development is slowing down because our test suite is such a headache," or "It's really slow. It's really flaky. It's really complicated." And that is a pain point that a lot of tech leaders are also looking to address for their teams. But I was really questioning this idea that, like, it always had to be some effort to improve the test suite, like, that had to be worked on at some later point or get, like, an initiative together to fix all of these problems, and that it couldn't just be baked into your normal development process, like, on an individual level. I do think it is really easy to feel a lot of pain when trying to write tests and then just be like, ugh, like, I wish someone would fix this, right? Or, you know, just kind of ignore the signals of that pain because you don't know, like, how to manage it yourself. So, my talk is about when you do feel that pain, really trying to determine if there's anything you can do, even in just, like, the one test file that you're working in to make things a little bit easier for yourself, so it doesn't become this, like, chronic issue that just gets worse and worse. Is there something you could do to maybe reorganize the file as you're working in it to make some conditionals a little bit clearer? Is there any, like, extra test setup that you're like, "Oh, actually, I don't need this anymore, and I can just start to get rid of it, not just for this one example, but for the rest in this file"? And do yourself a favor a little bit. So yeah, I'm excited to talk about that because I think that's perhaps, like, a skill that we don't focus enough on. JOËL: Are you going to sort of focus in on the side of things where, like, a classic TDD mantra is that test pain reflects underlying code complexity? So, are you planning to focus on the idea of, oh, if you're feeling test pain, maybe take some time to refactor some of the code that's under test, maybe because there's some tight coupling? Or are you going to lean a little bit more into maybe, like, the Boy Scout rule, you know, 'Leave the campsite cleaner than you found it' for your test files? STEPHANIE: Ooh, I like that framing. Definitely more of the former. But one thing I've also noticed working with a lot of client teams is that it's not always clear, like, how to refactor. I think a lot of intermediate developers start to feel that pain but don't know what to do about it. They don't know, like, maybe the code smells, or the patterns, or refactoring strategies, and that can certainly be taught. It will probably pull from that. But even if you don't know those skills yet, I'm wondering if there's, like, an opportunity to teach, like, developers at that level to start to reflect on the code and be like, "Hmm, what could I do to make this a little more flexible?" And they might not know the names of the strategies to, like, extract a class, but just start to get them thinking about it. And then maybe when they come across that vocabulary later, it'll connect a lot easier because they'll have started to think about, you know, their experiences day to day with some of the more conceptual stuff. JOËL: I really like that because I feel we've probably all heard that idea that test pain, especially when you're test driving, is a sign of maybe some anti-patterns or some code smells in the underlying code that you're testing. But translating that into something actionable and being able to say, "Okay, so my tests are painful. They're telling me something needs to be refactored. I'm looking at this code, and I don't know what to refactor." It's a big jump. It's almost the classic draw two circles; draw the rest of the owl meme. And so, I think bridging that gap is something that is really valuable for our community. STEPHANIE: Yeah, that's exactly what I hope to do in my talk. So, Joël, you [chuckles] also didn't quite mention that you have big news as well. JOËL: So, I also got accepted to speak at RailsConf. I'm giving a talk on Building a Dungeons & Dragons Character Sheet Using Turbo. STEPHANIE: That's really awesome. I'm excited because I want to learn more about Turbo. I want someone else to tell me [laughs] what I can do with it. And as a person with a little bit of Dungeons & Dragons experience, I think a character sheet is kind of the perfect vehicle for that. JOËL: Building a D&D character sheet has been kind of my go-to project to experiment with a new front-end framework because it's something that's pretty dynamic. And for those who don't know, there's a bunch of fields that you fill in with stats for different attributes that your character has, but then those impact other stats that get rendered. And sometimes there can be a chain two or three long where different numbers kind of combine together. And so, you've got this almost dependency tree of, like, a particular number. Maybe your skill at acrobatics might depend on a number that you entered in the dexterity field, but it also depends on your proficiency bonus, and maybe also depends on the race that you picked and a few other things. And so, calculating those numbers all of a sudden becomes not quite so simple. And so, I find it's a really fun exercise to build when trying out a new interactive front-end technology. STEPHANIE: Have you done this with a different implementation or a framework? JOËL: I've done this, not completely, but I've attempted some parts of a D&D character sheet, I think, with Backbone.js with Ember. I may have done an Angular one at some point in original Angular, so Angular 1. I did this with Elm. Somehow, I skipped React. I don't think I did React to build a D&D character sheet. And now I'm kind of moving a little bit back to the backend. How much can we get done just with Turbo? Or do we need to pull in maybe Stimulus? These are all things that are going to be really fun to demonstrate. STEPHANIE: Yeah. Speaking of injecting some whimsy earlier, I think it's kind of like just a little more fun than a regular to-do app, you know, or a blog to show how you can build, you know, something that people kind of understand with a different technology. JOËL: Another really fun thing that I've been toying with this week has been using AI to help me refactor code. And this has been using just sort of a classic chat AI, not a tool like Copilot. And I was dealing with a query that was really slow, and I wanted to restructure it in a different way. And I described to the AI how I wanted it to refactor and explicitly said, "I want this to be the same before and after." And I asked it to do the refactor, and it gave me some pretty disappointing results where it did some, like, a couple of really obvious things that were not that useful. And I was talking to a colleague about how I was really disappointed. I was thinking, well, AI should be able to do something better than this. And this colleague suggested changing the way I was asking for things and specifically asking for a step-by-step and asking it to prove every step using relational algebra, which is the branch of math that deals with everything that underlies relational databases, so the transformations that you would do where you keep everything the same, but you're saying, "Hey, these equations are all equivalent." And it sure did. It gave me a, like, 10-step process with all these, like, symbols and things. My relational algebra is not that strong, and so I couldn't totally follow along. But then I asked it to give me a code example, like, show me the SQL at every step of this transformation and at the end. And, you know, it all kind of looked all right. I've not fully tested the final result it gave me to see if it does what it says on the tin. But I'm cautiously optimistic. I think it looks very similar to something that I came up with on my own. And so, I'm somewhat impressed, at least, like, much better than things were in the beginning with that first round. So, I'm really curious to see where I can take this. STEPHANIE: Yeah, I think that's cool that you were able to prompt it differently and get something more useful. One of the reasons why I personally have been a little bit hesitant to get into the large language models is because I would love to see the AI show its work, essentially, like, tell me a little bit more about how it got from question to answer. And I thought that framing of kind of step-by-step show me code was a really interesting way, even to just, like, get some different results that do the same thing. But you can kind of evaluate that a little bit more on your own rather than just using that first result that it gave you that was like, eh, like, I don't know if this really did anything for me. So, it would be cool, even if you don't end up using, like, the final one, right? If something along the way also is an improvement from what you started with that would be really interesting. JOËL: Honestly, I think you kind of want the same thing if you're chatting with an AI chatbot or having a conversation in Slack with a colleague. They're just like, "Hey, can you help me refactor this?" And then a sort of, like, totally different chunk of code. And it's just like, "Trust me, it works." STEPHANIE: [laughs]. JOËL: And maybe it does. Maybe you plug it into your codebase and run the tests against it, and the tests are still green. And so, you trust that it works, but you don't really understand where it came from. That doesn't always feel good, even when it comes from a human. So, what I've appreciated with colleagues has been when they've given me a step-by-step. Sometimes, they give me the final product. They just say, "Hey. Try this. Does this work?" Plug it in to the test. It does pass. It's green. Great. "Tell me what black magic you did to get to that." And then they give me the step-by-step and it's like, oh, that's so good because not only do I get a better understanding of what happens at every step, but now I'm equipped the next time I run into this problem to apply the same technique to figure it out on my own. STEPHANIE: Yeah. And I liked, also, that relational algebra pro tip, right? It kind of ensures that what you're getting makes sense or is equivalent along the way [laughs]. JOËL: We think, right? I don't know enough relational algebra to check its work. It is quite possible that it is making some subtle mistakes along the way, or, like, making inferences that it shouldn't be. I'm not going to say I trust that. But I think, specifically, when asking for SQL transformations, prompting it to do so using relational algebra in a step-by-step way seemed to be a way to get it to do something more reliably or at least give more interesting results. STEPHANIE: Cool. JOËL: I was interested in trying this out in part because I've been more curious about AI tools recently, and also because we're hoping to do a deeper dive into AI on a Bike Shed episode at some point later, so very much still in the gathering information phase. But this was a really cool experience. So, having an AI refactor a query for me using relational algebra, definitely something that's new in my world this week. STEPHANIE: Speaking of refactoring and this idea of making improvements to your code and trying to figure out how to get from what you currently have to something new, I have been thinking a lot about how to make code reviews more actionable. And that's because, on my current client project, our team is struggling a little bit with code reviews, especially when you kind of want to give feedback on more of a design change in the code or thinking about some different abstractions. I have found that that is really hard to communicate async and also in a, like, a GitHub code review format where you can really just comment, like, line by line. And I've found that, you know, when someone is leaving feedback, that's like, "I'm having a hard time reading this. And I'm imagining that we could organize the code a bit differently in these three different layers or abstractions," there's a lot of assumptions there, right [laughs]? That your message is being communicated to the author and that they are able to, like, visualize, or have a mental model for what you're explaining as well. And then kind of what I've been seeing in this dynamic is, like, not really knowing what to do with that and to kind of just, like, I don't know where to go from here. So, I guess the next step is just to, like, merge it. Is that something you've experienced before or encountered when it comes to feedback? JOËL: Broader changes are often challenging to explain, especially when they're...sometimes you get so abstract you can just write a quick paragraph. And sometimes it's like, hey, what if we, like, totally change our approach? I've definitely done the thing where I'll just ping someone and say, "Hey, can we talk about this synchronously? Can we get on a call and have a deeper conversation?" How do you tend to approach if you're not going to hop on a call with someone and, like, have a 20 or 30-minute conversation? How do you approach doing that asynchronously on a pull request? Are you the type of person to put, like, a ton of, like, code blocks, like, "Here's what I was thinking. We could instead have this class and this thing"? And, like, pretty soon, it's, like, a page and a half of text. Or do you have another approach that you like to use? STEPHANIE: Yeah. And I think that's where it can get really interesting. Because my process is, I'll usually just start commenting and maybe if I'm seeing some things that can be done differently. If it's not just, like, a really obvious change that I could just use English to describe, I'll add a little suggested change. But I also don't want to just rewrite this person's code [laughs] in a code review. JOËL: That's the challenge, right? STEPHANIE: Yeah. And I've definitely seen that be done before, too. Once I notice I'm at, like, four plus comments, and then they're not just, like, nitpicks about, like, syntax or something like that, that helps me clue into the idea that there is some kind of bigger change that I might be asking of the author. And I don't want to overwhelm them with, like, individual comments that really are trying to convey something more holistic. JOËL: Right. I wonder if having a, like, specialized yet more abstract language is useful for these sorts of things where a whole paragraph in English or, you know, a ton of code examples might be a bit much. If you're able to say something like, "Hey, how would you feel about using a strategy pattern approach here instead of, you know, maybe a template object or some custom thing that we've built here?" that allows us to say a lot in a fairly sort of terse way. And it's the thing that you can leave more generically on the PR instead of, like, individually commenting in a bunch of places. And that can start a broader conversation at more of an architecture level. STEPHANIE: Yes, I really like that. That's a great idea. I would follow that up with, like, I think at the end of the day, there are some conversations that do need to be had synchronously. And so, I like the idea of leaving a comment like that and just kind of giving them resources to learn what a strategy pattern is and then offering support because that's also a way to shorten that feedback loop of trying to communicate an idea. And I like that it's kind of guiding them, but also you're there to add some scaffolding if it ends up being, like, kind of a big ask for them to figure out what to do. JOËL: There's also oftentimes, I think, a tone thing to manage where, especially if there's a difference in seniority or experience between the two people, it can be very easy for something to come across as an ask or a demand rather than a like, "Hey, let's think about some alternatives here." Or, like, "I have some concerns with your implementation. Let's sort of broadly explore some possible alternatives. Maybe a strategy pattern works." But the person reading that who wrote the original code might be, like, receiving that as "Your code is bad. You should have done a strategy pattern instead." And that's not the conversation I want to have, right? I want to have a back-and-forth about, "Hey, what are the trade-offs involved? Do you have a third architecture you'd like to suggest?" And so, that can be a really tricky thing to avoid. STEPHANIE: Yeah, I like that what you're saying also kind of suggested that it's okay if you don't have an idea yet for exactly how it should look like. Maybe you just are like, oh, like, I'm having a hard time understanding this, but I don't think just leaving it at that gives the author a lot to go on. I think there's something to it about maybe the action part of actionable is just like, "Can you talk about it with me?" Or "Could you explain what you're trying to do here?" Or, you know, leave a comment about what this method is doing. There's a lot of ways, I think, that you can reach some amount of improvement, even if it doesn't end up being, like, the ideal code that you would write. JOËL: Yes. There's also maybe a distinction in making it actionable by giving someone some code and saying, "Hey, you should copy-paste this code and make that..." or, you know, use a GitHub suggested code or something, which works on the small. And in the big, you can give some maybe examples and say, "Hey, what if you refactored in this way?" But sometimes, you could even step back and let them do that work and say, "Hey, I have some concerns with the current architecture. It's not flexible in the ways that we need to be flexible. Here's my understanding of the requirements. And here's sort of how I see maybe this architecture not working with that. Let's think of some different ways we could approach this problem." And oftentimes, it's nice to give at least one or two different ideas to help start that. But it can be okay to just ask the person, "Hey, can you come up with some alternate implementations that would fulfill these sets of requirements?" STEPHANIE: Yeah, I like that. And I can even see, like, maybe you do that work, and you don't end up pursuing it completely in addressing that feedback. But even asking someone to do the exercise itself, I think, can then spark new ideas and maybe other improvements. In general, I like to think about...I'm a little hesitant to use this metaphor because I'm not actually giving code, like, letter grades when I review them, but the idea that, like, not all code has to get, like, an A [chuckles], but maybe getting it, like, from one letter grade up to, like, half a letter grade, like, higher, that is valuable, even if it's not always practical to go through multiple rounds of code review. And I think just making it actionable enough to be a little bit better, like, that is, in my opinion, the sweet spot. JOËL: That's true. The sort of over-giving feedback to someone to try to get code perfect, rather than just saying, "Hey, can we make it slightly better?" And, you know, there are probably some minimum standards you need to hit. But at some point, it's a trade-off of like, how much time do we need to put polishing this versus shipping something? STEPHANIE: Yeah, and I think that it is cumulative over time, right? That's how people learn. Yeah, it's like one of the biggest opportunities for developers to level up is from that feedback. And that's why I think it's important that it's actionable because, you know, and you put the time into, like, giving that review, and it's not just to make sure the code works, but it's also, like, one of the touch points for collaboration. JOËL: So, if you had to summarize what makes code review comments actionable, do you have, like, top three tips that make a comment really actionable as opposed to something that's not helpful? Or maybe that's more of the journey that you're on, and you've not distilled it down to three pithy tips that you can put in a listicle. STEPHANIE: Honestly, I think it does kind of just distill down to one, which is for every comment, you should have an idea of what you would like the author to do about it. And it's okay if it's nothing, but then tell them that it's nothing. You could just be expressing, "I thought this was kind of weird, [laughs]" or "This is not my favorite thing, but it's okay." JOËL: And it can be okay for the thing you want the author to do. It doesn't have to be code. It could be a conversation. STEPHANIE: Yeah, exactly. It could be a conversation. It could be asking for information, too, right? Like, "Did you consider alternatives, and could you share them with me?" But that request portion, I think is really important because, yeah, I think there's so much miscommunication that can happen along the way. So, definitely still trying to figure out how to best support that kind of code review culture on my team. JOËL: This week's episode has been really fun because it's just been a combination of a lot of things that are new in our world, things that we've been trying, things that we've been learning. And kind of in an almost, like, a meta sense, one of the things I've been digging into is combinatorics, the branch of math that looks at how things combine and particularly how it works with combining a bunch of ActiveRecord query fragments where there's potential branching, so things like doing a union of two sort of sub queries or doing an or where you're combining two different where queries and trying to figure out what are the different paths through that. STEPHANIE: Wow, what a great way to combine what we were talking about, Joël [laughs]. Did you apply combinatorics to this podcast episode [laughs]? JOËL: Somehow, topics multiply with each other, something, something. STEPHANIE: Yeah, that makes sense to me [laughs]. Okay. Will you tell me more about what you've been using it for in your queries? JOËL: So, one thing I'm trying to do is because I've got these different branching paths through a query, I want to see sort of all the different ways because these are defined as ActiveRecord scopes, and I'm chaining them together. And it looks linear because I'm calling scope1 dot scope2 dot scope3. But each of those have branches inside of them. And so, there's all these different ways that data could get used or not. And one way that I figured out, like, what are the different paths here, was actually drawing out a matrix, just putting together a table. In this case, I had two scopes, each of which had a two-way branch inside, and so I made a two by two matrix. And that gave me all of the combinations of, oh, if you go down one branch in one scope and down another branch in the other scope. And what I went through is then I went in in each square and filled in how many records I would expect to get back from the query from some basic set that I was working on in each of these combinations. And one thing that was really interesting is that some of those combinations were sort of mutually exclusive, where a scope further down the line was filtering on the same field as an earlier one and would overwrite it or not overwrite it, but the two would then sort of you can't have both of those things be true at the same time. So, I'm looking for something that has a particular manager ID, and then I'm looking for something that has a particular different manager ID. And the way Rails combines these, if you just change scopes with where, is to and them together. There are no records that have both manager ID 1 and manager ID 2. You can only have one manager ID. And so, as I'm filling out my matrix, there's some sections I can just zero out and be like, wait, this will always return zero record. And then I can start focusing on the parts that are not zeroed out. So, I've got two or three squares. What's special about those? And that helped me really understand what the combination of these multiple query fragments together were actually trying to do as a holistic whole. STEPHANIE: Wow, yeah, that is really interesting because I hear you when you say it looks linear. And it would be really surprising to me for there to be branching paths. Like, that's not really what I think about when I think about SQL. But that makes a lot of sense that it could get so complicated that it's just impossible to get a certain kind of result. Like, what's going to be the outcome of applying combinatorics to this? Is there a refactoring opportunity, or is it really just to even understand what's going on? JOËL: So, this was a refactoring that I was trying to do, but I didn't really understand the underlying behavior of the chain of scopes. I just knew that they were doing some complex things that were inefficient from a SQL perspective. And so, I was looking at ways to refactor, but I also wanted to get a sense of what is this actually trying to do other than just chaining a bunch of random bits of code together? So, the matrix really helped for that. The other way that I used it was to write some tests because this query I was trying to refactor, this chain of scopes, was untested. And I wanted to write tests that were very thorough because I wanted to make sure that my refactor didn't break any edge cases. And I'm, you know, writing a few tests. Okay, well, here's a record that I definitely want to get returned by this query, and maybe here are a couple of records I don't want to get returned. And the more I was, like, going into this and trying to write test cases, the more I was finding more edge cases that I didn't want to and, oh, but what about this? And what about the combination of these things? And it got to the point where it was just messing with my mind. I was, like, confusing myself and really struggling to write tests that would do anything useful. STEPHANIE: Wow. Yeah. Honestly, I have already started to become a little bit suspicious of complex scopes, and this further pushes me in that direction [laughs] because yeah, once you start to...like, the benefit of them is that you can chain them, but it really hides a lot of the underlying behavior. So, you can easily just turn yourself around or, like, go, you know, kind of end up [laughs] in a little bit of a bind. JOËL: Definitely, especially once it grows a little bit harder to hold in your head. And I don't know exactly where that level is for me. But in this particular situation, I identified, I think, five different dimensions that would impact the results of this query. And then each dimension had maybe three or four different values that we might care about. And, eventually, I just took the time to write this out. So, I created five arrays and then just said, "Hey, here are the different managers that we care about. Here are the different project types we care about. Here are the different..." and we had, like, five of these, and each array had three or four elements in it. And then, in a series of nested loops, I iterated through all of these arrays and at the innermost loop, created the data that I wanted that matched that particular set of values. Now, we're often told you should not be doing things in nested loops because you end up sort of multiplying all of these together, but, in this case, this is actually what I wanted to do. You know, it turns out that I had a hundred-ish records I had to create to sort of create a data set that would be all the possible edge cases I might want to filter on. And creating them all by hand with all of the different variations was going to be too much. And so, I ended up doing this with arrays and nested loops. And it got me the data that I needed. And it gave me then the confidence to know that my refactor did indeed work the way I was expecting. STEPHANIE: Wow. That's truly hero's work [chuckles]. I'm, like, very excited because it sounds like that's a huge opportunity for some performance improvements as well. JOËL: For the underlying code, yes. The test might be a little bit slow because I'm creating a hundred records in the database. And you might say, "Oh, do you really need to do that? Can you maybe collapse some of these cases?" In this particular case, I really wanted to have high confidence that the refactor was not changing anything. And so, I was okay creating a hundred records over a series of nested iterations. That was a price I was willing to pay. The refactored query, it turns out, I was able to write it in a way that was significantly faster. STEPHANIE: Yeah, that's what I suspected. JOËL: So, I had to rewrite it in a way that didn't take advantage of all the change scopes. I had to just sort of write something custom from scratch, which is often the case, right? Performance and reusability sometimes fight against each other, and it's a trade-off. So, I'm not reusing the scopes. I had to write something from scratch, but it's multiple hundreds of times faster. STEPHANIE: Wow. Yeah. That seems worth it for a slow test [laughs] for the user experience to be a lot better, especially when you just reach that level of complexity. And it's a really awesome strategy that you applied to figure that out. I think it's a very unique one [laughs]. That's for sure. JOËL: I've had an interest in sort of analytical tools to help me understand domain models, to help understand problems, to help understand code that I'm working with for a while now, and I think an understanding of combinatorics fits into that. And then, particular tools within that, such as drawing things out in a table, in a two by two matrix, or an end-by-end matrix to get something visual, that's a great tool for debugging or understanding a problem. Thinking of problems as data that exists in multiple dimensions and then asking about the cardinality of that set it's the kind of analysis I did a lot when I was modeling using algebraic data types in Elm. But now I've sort of taken some of the tools and analysis I use from that world into thinking about things like SQL records, things like dealing with data in Ruby. And I'm able to bring those tools and that way of thinking to help me solve some problems that I might struggle to solve otherwise. For any of our listeners who this, like, kind of piques their interest, combinatorics falls under a broader umbrella of mathematics called discrete math. And within that, there's a lot that I think is really useful, a lot of tools and techniques that we can apply to our day-to-day programming. We have a Bike Shed episode where we talked about is discrete math relevant to day-to-day programmers and what are the ways it's so? We'll link that in the show notes. I also gave a talk at RailsConf last year diving into that titled: The Math Every Programmer Needs. So, if you're looking for something that's accessible to someone who's not done a math degree, those are two great jumping-off points. STEPHANIE: Yeah. And then, maybe you'll start drawing out arrays and applying combinatorics to figure out your performance problems. JOËL: On that note, shall we wrap up? STEPHANIE: Let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeeeee!!!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at: tbot.io/referral. Or you can email us at: referrals@thoughtbot.com with any questions.
Joël talks about his difficulties optimizing queries in ActiveRecord, especially with complex scopes and unions, resulting in slow queries. He emphasizes the importance of optimizing subqueries in unions to boost performance despite challenges such as query duplication and difficulty reusing scopes. Stephanie discusses upgrading a client's app to Rails 7, highlighting the importance of patience, detailed attention, and the benefits of collaborative work with a fellow developer. The conversation shifts to Ruby's reduce method (inject), exploring its complexity and various mental models to understand it. They discuss when it's preferable to use reduce over other methods like each, map, or loops and the importance of understanding the underlying operation you wish to apply to two elements before scaling up with reduce. The episode also touches on monoids and how they relate to reduce, suggesting that a deep understanding of functional programming concepts can help simplify reduce expressions. Rails 7 EXPLAIN ANALYZE (https://www.bigbinary.com/blog/rails-7-1-adds-options-to-activerecord-relation-explain) Blocks, symbol to proc, and symbols arguments for reduce (https://thoughtbot.com/blog/blocks-procs-and-enumerable) Ruby tally (https://medium.com/@baweaver/ruby-2-7-enumerable-tally-a706a5fb11ea) Performance considerations for reduce in JavaScript (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce#when_to_not_use_reduce) Persistant data structures (https://www.youtube.com/watch?v=gTClDj9Zl1g) Avoid passing a block to map and reduce (https://thoughtbot.com/blog/avoid-putting-logic-in-map-blocks) Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire (https://ris.utwente.nl/ws/portalfiles/portal/6142049/meijer91functional.pdf) monoids (https://blog.ploeh.dk/2017/10/06/monoids/) iteration anti-patterns (https://thoughtbot.com/blog/iteration-as-an-anti-pattern) Joël's talk on “constructor replacement” (https://www.youtube.com/watch?v=dSMB3rsufC8) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: I've been doing a bunch of fiddling with query optimization this week, and I've sort of run across an interesting...but maybe it's more of an interesting realization because it's interesting in the sort of annoying way. And that is that, using ActiveRecord scopes with certain more complex query pieces, particularly unions, can lead to queries that are really slow, and you have to rewrite them differently in a way that's not reusable in order to make them fast. In particular, if you have sort of two other scopes that involve joins and then you combine them using a union, you're unioning two sort of joins. Later on, you want to change some other scope that does some wares or something like that. That can end up being really expensive, particularly if some of the underlying tables being joined are huge. Because your database, in my case, Postgres, will pull a lot of this data into the giant sort of in-memory table as it's, like, building all these things together and to filter them out. And it doesn't have the ability to optimize the way it would on a more traditional relation. A solution to this is to make sure that the sort of subqueries that are getting unioned are optimized individually. And that can mean moving conditions that are outside the union inside. So, if I'm chaining, I don't know, where active is true on the outer query; on the union itself, I might need to move that inside each of the subqueries. So, now, in the two or three subqueries that I'm unioning, each of them needs to have a 'where active true' chained on it. STEPHANIE: Interesting. I have heard this about using ActiveRecord scopes before, that if the scopes are quite complex, chaining them might not lead to the most performant query. That is interesting. By optimizing the subqueries, did you kind of change the meaning of them? Was that something that ended up happening? JOËL: So, the annoying thing is that I have a scope that has the union in it, and it does some things sort of on its own. And it's used in some places. There are also other places that will try to take that scope that has the union on it, chain some other scopes that do other joins and some more filters, and that is horribly inefficient. So, I need to sort of rewrite the sort of subqueries that get union to include all these new conditions that only happen in this one use case and not in the, like, three or four others that rely on that union. So, now I end up with some, like, awkward query duplication in different call sites that I'm not super comfortable about, but, unfortunately, I've not found a good way to make this sort of nicely reusable. Because when you want to chain sort of more things onto the union, you need to shove them in, and there's no clean way of doing that. STEPHANIE: Yeah. I think another way I've seen this resolved is just writing it in SQL if it's really complex and it becoming just a bespoke query. We're no longer trying to use the scope that could be reusable. JOËL: Right. Right. In this case, I guess, I'm, like, halfway in between in that I'm using the ActiveRecord DSL, but I am not reusing scopes and things. So, I sort of have the, I don't know, naive union implementation that can be fine in all of the simpler use cases that are using it. And then the query that tries to combine the union with some other fancy stuff it just gets its own separate implementation different than the others that it has optimized. So, there are sort of two separate paths, two separate implementations. I did not drop down to writing raw SQL because I could use the ActiveRecord DSL. So, that's what I've been working with. What's new in your world this week? STEPHANIE: So, a couple of weeks ago, I think, I mentioned that I was working on a Rails 7 upgrade, and we have gotten it out the door. So, now the client application I'm working on is on Rails 7, which is exciting for the team. But in an effort to make the upgrade as incremental as possible, we did, like, back out of a few of the new application config changes that would have led us down a path of more work. And now we're kind of following up a little bit to try to turn some of those configs on to enable them. And it was very exciting to kind of, like, officially be on Rails 7. But I do feel like we tried to go for, like, the minimal amount of work possible in that initial big change. And now we're having to kind of backfill a little bit on some of the work that was a little bit more like, oh, I'm not really sure, like, how big this will end up being. And it's been really interesting work, I think, because it requires, like, two different mindsets. Like, one of them is being really patient and focused on tedious work. Like, okay, what happens when we enable this config option? Like, what changes? What errors do we see? And then having to turn it back off and then go in and fix them. But then another, I think, like, headspace that we have to be in is making decisions about what to do when we come to a crossroads around, like, okay, now that we are starting to see all the changes that are coming about from enabling this config, is this even what we want to do? And it can be really hard to switch between those two modes of thinking. JOËL: Yeah. How do you try to balance between the two? STEPHANIE: So, I luckily have been pairing with another dev, and I've actually found that to be really effective because he has, I guess, just, like, a little bit more of that patience to do the more tedious, mundane [laughs] aspects of, like, driving the code changes. And I have been riding along. But then I can sense, like, once he gets to the point of like, "Oh, I'm not sure if we should keep going down this road," I can step in a little bit more and be like, "Okay, like, you know, I've seen us do this, like, five times now, and maybe we don't want to do that." Or maybe being like, "Okay, we don't have a really clear answer, but, like, who can we talk to to find out a little bit more or get their input?" And that's been working really well for me because I've not had a lot of energy to do more of that, like, more manual or tedious labor [chuckles] that comes with working on that low level of stuff. So yeah, I've just been pleasantly surprised by how well we are aligning our superpowers. JOËL: To use some classic business speech, how does it feel to be in the future on Rails 7? STEPHANIE: Well, we're not quite up, you know, up to modern days yet, but it does feel like we're getting close. And, like, I think now we're starting to entertain the idea of, like, hmm, like, could we be even on main? I don't think it's really going to happen, but it feels a little bit more possible. And, in general, like, the team thinks that that could be, like, really exciting. Or it's easier, I think, once you're a little bit more on top of it. Like, the worst is when you get quite behind, and you end up just feeling like you're constantly playing catch up. It just feels a little bit more manageable now, which is good. JOËL: I learned this week a fun fact about Rails 7.1, in particular, which is that the analyze method on ActiveRecord queries, which allowed you to sort of get SQL EXPLAIN statements, now has the ability to pass in a couple of extra parameters. So, there are symbols, and you can pass in things like analyze or verbose, which allows you to get sort of more data out of your EXPLAIN query, which can be quite nice when you're debugging for performance. So, if you're in the future and you're on Rails 7.1 and you want sort of the in-depth query plans, you don't need to copy the SQL into a Postgres console to get access to the sort of fully developed EXPLAIN plan. You can now do it by passing arguments to EXPLAIN, which I'm very happy for. STEPHANIE: That's really nice. JOËL: So, we've mentioned before that we have a developers' channel on Slack here at thoughtbot, and there's all sorts of fun conversations that happen there. And there was one recently that really got me interested, where people were talking about Ruby's reduce method, also known as inject. And it's one of those methods that's kind of complicated, or it can be really confusing. And there was a whole thread where people were talking about different mental models that they had around the reduce method and how they sort of understand the way it works. And I'd be curious to sort of dig into each other's mental models of that today. To kick us off, like, how comfortable do you feel with Ruby's reduce method? And do you have any mental models to kind of hold it in your head? STEPHANIE: Yeah, I think reduce is so hard to wrap your head around, or it might be one of the most difficult, I guess, like, functions a new developer encounters, you know, in trying to understand the tools available to them. I always have to look up the order of the arguments [laughs] for reduce. JOËL: Every time. STEPHANIE: Yep. But I feel like I finally have a more intuitive sense of when to use it. And my mental model for it is collapsing a collection into one value, and, actually, that's why I prefer calling it reduce rather than the inject alias because reduce kind of signals to me this idea of going from many things to one canonical thing, I suppose. JOËL: Yeah, that's a very common use case for reducing, and I guess the name itself, reducing, kind of has almost that connotation. You're taking many things, and you're going to reduce that down to a single thing. STEPHANIE: What was really interesting to me about that conversation was that some people kind of had the opposite mental model where it made a bit more sense for them to think about injecting and, specifically, like, the idea of the accumulator being injected with values, I suppose. And I kind of realized that, in some ways, they're kind of antonyms [chuckles] a little bit because if you're focused on the accumulator, you're kind of thinking about something getting bigger. And that kind of blew my mind a little bit when I realized that, in some ways, they can be considered opposites. JOËL: That's really fascinating. It is really interesting, I think, the way that we can take the name of a method and then almost, like, tell ourselves a story about what it does that then becomes our way of remembering how this method works. And the story we tell for the same method name, or in this case, maybe there's a few different method names that are aliases, can be different from person to person. I know I tend to think of inject less in terms of injecting things into the accumulator and more in terms of injecting some kind of operator between every item in the collection. So, if we have an array of numbers and we're injecting plus, in my mind, I'm like, oh yeah, in between each of the numbers in the collection, just inject a little plus sign, and then do the math. We're summing all the items in the collection. STEPHANIE: Does that still hold up when the operator becomes a little more complex than just, you know, like, a mathematical operator, like, say, a function? JOËL: Well, when you start passing a block and doing custom logic, no, that mental model kind of falls apart. In order for it to work, it also has to be something that you can visualize as some form of infix operator, something that goes between two values rather than, like, a method name, which is typically in prefix position. I do want to get at this idea, though: the difference between sort of the block version versus passing. There are ways where you can just do a symbol, and that will call a method on each of the items. Because I have a bit of a hot take when it comes to writing reduce blocks or inject blocks that are more accessible, easier to understand. And that is, generally, that you shouldn't, or more specifically, you should not have a big block body. In general, you should be either using the symbol version or just calling a method within the block, and it's a one-liner. Which means that if you have some complex behavior, you need to find a way to move that out of this sort of collection operation and into instance methods on the objects being iterated. STEPHANIE: Hmm, interesting. By one-liner do you mean passing the name of the method as a proc or actually, like, having your block that then calls the method? Because I can see it becoming even simpler if you have already extracted a method. JOËL: Yeah, if you can do symbol to proc, that's amazing, or even if you can use just the straight-up symbol way of invoking reduce or inject. That typically means you have to start thinking about the types of objects that you are working with and what methods can be moved onto them. And sometimes, if you're working with hashes or something like that that don't have domain methods for what you want, that gets really awkward. And so, then maybe that becomes maybe a hint that you've got some primitive obsession happening and that this hash that sort of wants a domain object or some kind of domain method probably should be extracted to its own object. STEPHANIE: I'll do you with another kind of spicy take. I think, in that case, maybe you don't want a reduce at all. If you're starting to find that...well, okay, I think it maybe could depend because there could be some very, like, domain-specific logic. But I have seen reduce end up being used to transform the structure of the initial collection when either a different higher-order function can be used or, I don't know, maybe you're just better off writing it with a regular loop [laughs]. It could be clearer that way. JOËL: Well, that's really interesting because...so, you mentioned the idea that we could use a different higher-order function, and, you know, higher-order function is that fancy term, just a method that accepts another method as an argument. In Ruby, that just means your method accepts a block. Reduce can be used to implement pretty much the entirety of enumerable. Under the hood, enumerable is built in terms of each. You could implement it in terms of reduce. So, sometimes it's easy to re-implement one of the enumerable methods yourself, accidentally, using reduce. So, you've written this, like, complex reduce block, and then somebody in review comes and looks at it and is like, "Hey, you realize that's just map. You've just recreated map. What if we used map here?" STEPHANIE: Yeah. Another one I've seen a lot in JavaScript land where there are, you know, fewer utility functions is what we now have in Ruby, tally. I feel like that was a common one I would see a lot when you're trying to count instances of something, and I've seen it done with reduce. I've seen it done with a for each. And, you know, I'm sure there are libraries that actually provide a tally-like function for you in JS. But I guess that actually makes me feel even more strongly about this idea that reduce is best used for collapsing something as opposed to just, like, transforming a data structure into something else. JOËL: There's an interesting other mental model for reduce that I think is hiding under what we're talking about here, and that is the idea that it is a sort of mid-level abstraction for dealing with collections, as opposed to something like map or select or some of those other enumerable helpers because those can all be implemented in terms of reduce. And so, in many cases, you don't need to write the reduce because the library maintainer has already used reduce or something equivalent to build these higher-level helpers for you. STEPHANIE: Yeah, it's kind of in that weird point between, like, very powerful [chuckles] so that people can start to do some funky things with it, but also sometimes just necessary because it can feel a little bit more concise that way. JOËL: I've done a fair amount of functional programming in languages like Elm. And there, if you're building a custom data structure, the sort of lowest-level way you have of looping is doing a recursion, and recursions are messy. And so, what you can do instead as a library developer is say, "You know what, I don't want to be writing recursions for all of these." I don't know; maybe I'm building a tree library. I don't want to write a recursion for every different function that goes over trees if I want to map or filter or whatever. I'm going to write reduce using recursion, and then everything else can be written in terms of reduce. And then, if people want to do custom things, they don't need to recurse over my tree. They can use this reduce function, which allows them to do most of the traversals they want on the tree without needing to touch manual recursion. So, there's almost, like, a low-level, mid-level, high-level in the library design, where, like, lowest level is recursion. Ideally, nobody touches that. Mid-level, you've got reducing that's built out on top of recursion. And then, on top of that, you've got all sorts of other helpers, like mapping, like filtering, things like that. STEPHANIE: Hmm. I'm wondering, do you know of any performance considerations when it comes to using reduce built off a recursion? JOËL: So, one of the things that can be really nice is that writing a recursion yourself is dangerous. It's so easy to, like, accidentally introduce Stack Overflow. You could also write a really inefficient one. So, ideally, what you do is that you write a reduce that is safe and that is fast. And then, everybody else can just use that to not have to worry about the sort of mechanics of traversing the collection. And then, just use this. It already has all of the safety and speed features built in. You do have to be careful, though, because reduce, by nature, traverses the entire collection. And if you want to break out early of something expensive, then reduce might not be the tool for you. STEPHANIE: I was also reading a little bit about how, in JavaScript, a lot of developers like to stick to that idea of a pure function and try to basically copy the entire accumulator for every iteration and creating a new object for that. And that has led to some memory issues as well. As opposed to just mutating the accumulator, having, especially when you, you know, are going through a collection, like, really large, making that copy every single time and creating, yeah [chuckles], just a lot of issues that way. So, that's kind of what prompted that question. JOËL: Yeah, that can vary a lot by language and by data structure. In more functional languages that try to not mutate, they often have this idea of what they call persistent data structures, where you can sort of create copies that have small modifications that don't force you to copy the whole object under the hood. They're just, like, pointers. So, like, hey, we, like, are the same as this other object, but with this extra element added, or something like that. So, if you're growing an array or something like that, you don't end up with 10,000 copies of the array with, like, a new element every time. STEPHANIE: Yeah, that is interesting. And I feel like trying to adopt different paradigms for different tools, you know, is not always as straightforward as some wish it were [laughs]. JOËL: I do want to give a shout-out to an academic paper that is...it is infamously dense. The title of it is Functional Programming with Bananas, Lenses, and Barbed Wire. STEPHANIE: It doesn't sound dense; it sounds fun. Well, I don't about barbed wire. JOËL: It sounds fun, right? STEPHANIE: Yeah, but certainly quirky [laughs]. JOËL: It is incredibly dense. And they've, like, created this custom math notation and all this stuff. But the idea that they pioneered there is really cool, this idea that kind of like I was talking about sort of building libraries in different levels. Their idea is that recursion is generally something that's unsafe and that library and language designers should take care of all of the recursion and instead provide some of these sort of mid-level helper methods to do things. Reducing is one of them, but their proposal is that it's not the only one. There's a whole sort of family of similar methods that are there that would be useful in different use cases. So, reduce allows you to sort of traverse the whole thing. It does not allow you to break out early. It does not allow you to keep sort of track of a sort of extra context element if you want to, like, be traversing a collection but have a sort of look forward, look back, something like that. So, there are other variations that could handle those. There are variations that are the opposite of reduce, where you're, like, inflating, starting from a few parameters and building a collection out of them. So, this whole concept is called recursion schemes, and you can get, like, really deep into some theory there. You'll hear fancy words like catamorphisms and anamorphisms. There's a whole world to explore in that area. But at its core, it's this idea that you can sort of slice up things into this sort of low-level recursion, mid-level helpers, and then, like, kind of userland helpers built on top of that. STEPHANIE: Wow. That is very intense; it sounds like [chuckles]. I'm happy not to ever have to write a recursion ever again, probably [laughs]. Have you ever, as just a web developer in your day-to-day programming, found a really good use case for dropping down to that level? Or are you kind of convinced that, like, you won't really ever need to? JOËL: I think it depends on the paradigm of the language you're working in. In Ruby, I've very rarely needed to write a recursion. In something like Elm, I've had to do that, eh, not infrequently. Again, it depends, like, if I'm doing more library-esque code versus more application code. If I'm writing application code and I'm using an existing, let's say, tree library, then I typically don't need to write a recursion because they've already written traversals for me. If I'm making my own and I have made my own tree libraries, then yes, I'm writing recursions myself and building those traversals so that other people don't have to. STEPHANIE: Yeah, that makes sense. I'd much rather someone who has read that paper [laughs] write some traversal methods for me. JOËL: And, you know, for those who are curious about it, we will put a link to this paper in the description. So, we've talked about a sort of very academic mental model way of thinking about reducing. I want to shift gears and talk about one that I have found is incredibly practical, and that is the idea that reduce is a way to scale an operation that works on two objects to an operation that works on sort of an unlimited number of objects. To make it more concrete, take something like addition. I can add two numbers. The plus operator allows me to take one number, add another, get a sum. But what if I want to not just add two numbers? I want to add an arbitrary number of numbers together. Reduce allows me to take that plus operator and then just scale it up to as many numbers as I want. I can just plug that into, you know, I have an array of numbers, and I just call dot reduce plus operator, and, boom, it can now scale to as many numbers as I want, and I can sum the whole thing. STEPHANIE: That dovetails quite nicely with your take earlier about how you shouldn't pass a block to reduce. You should extract that into a method. Don't you think? JOËL: I think it does, yes. And then maybe it's, like, sort of two sides of a coin because I think what this leads to is an approach that I really like for reducing because sometimes, you know, here, I'm starting with addition. I'm like, oh, I have addition. Now, I want to scale it up. How do I do that? I can use reduce. Oftentimes, I'm faced with sort of the opposite problem. I'm like, oh, I need to add all these numbers together. How do I do that? I'm like, probably with a reduce. But then I start writing the block, and, like, I get way too into my head about the accumulator and what's going to happen. So, my strategy for writing reduce expressions is to, instead of trying to figure out how to, like, do the whole thing together, first ask myself, how do I want to combine any two elements that are in the array? So, I've got an array of numbers, and I want to sum them all. What is the thing I need to do to combine just two of those? Forget the array. Figure that out. And then, once I have that figured out, maybe it's an existing method like plus. Maybe it's a method I need to define on it if it's a custom object. Maybe it's a method that I write somewhere. Then, once I have that, I can say, okay, I can do it for two items. Now, I'm going to scale it up to work for the whole array, and I can plug it into reduce. And, at that point, the work is already basically done, so I don't end up with a really complex block. I don't end up, like, almost ending in, like, a recursive infinite loop in my head because I do that. STEPHANIE: [laughs]. JOËL: So, that approach of saying, start by figuring out what is the operation you want to do to combine two elements, and then use reduce as a way to scale that to your whole array is a way that I've used to keep things simple in my mind. STEPHANIE: Yeah, I like that a lot as a supplement to the model I shared earlier because, for me, when I think about reducing as, like, collapsing into a value, you kind of are just like, well, okay, I start with the collection, and then somehow I get to my single value. But the challenge is figuring out how that happens [laughs], like, the magic that happens in between that. And I think another alias that we haven't mentioned yet for reduce that is used in a lot of other languages is fold. And I actually like that one a lot, and I think it relates to your mental model. Because when I think about folding, I'm picturing folding up a paper like an accordion. And you have to figure out, like, what is the first fold that I can make? And just repeating that over and over to get to your little stack of accordion paper [laughs]. And if you can figure out just that first step, then you pretty much, like, have the recipe for getting from your initial input to, like, your desired output. JOËL: Yeah. I think fold is interesting in that some languages will make a distinction between fold and reduce. They will have both. And typically, fold will require you to pass an initial value, like a starting accumulator, to start it off. Whereas reduce will sort of assume that your array can use the first element of the array as the first accumulator. STEPHANIE: Oh, I just came up with another visual metaphor for this, which is, like, folding butter into croissant pastry when the butter is your initial value [laughs]. JOËL: And then the crust is, I guess, the elements in the array. STEPHANIE: Yeah. Yeah. And then you get a croissant out of it [laughs]. Don't ask me how it gets to a perfectly baked, flaky, beautiful croissant, but somehow that happens [laughs]. JOËL: So, there's an interesting sort of subtlety here that I think happens because there are sort of two slightly different ways that you can interact with a reduce. Sometimes, your accumulator is of the same type as the elements in your array. So, you're summing an array of numbers, and your accumulator is the sum, but each of the elements in the array are also numbers. So, it's numbers all the way through. And sometimes, your accumulator has a different type than the items in the array. So, maybe you have an array of words, and you want to get the sum of all of the characters and all the words. And so, now your accumulator is a number, but each of the items in the array are strings. STEPHANIE: Yeah, that's an interesting distinction because I think that's where you start to see the complex blocks being passed and reduced. JOËL: The complex blocks, definitely; I think they tend to show up when your accumulator has a different type than the individual items. So, maybe that's, like, a slightly more complicated use case. Oftentimes, too, the accumulator ends up being some, like, more complex, like, hash or something that maybe would really benefit from being a custom object. STEPHANIE: I've never done that before, but I can see why that would be really useful. Do you have an example of when you used a custom object as the accumulator? JOËL: So, I've done it for situations where I'm working with objects that are doing tally-like operations, but I'm not doing just a generic tally. There's some domain-specific stuff happening. So, it's some sort of aggregate counter on multiple dimensions that you can use, and that can get really ugly. And you can either do it with a reduce or you can have some sort of, like, initial version of the hash outside and do an each and mutate the hash and stuff like that. All of these tend to be a little bit ugly. So, in those situations, I've often created some sort of custom object that has some instance methods that allow to sort of easily add new elements to it. STEPHANIE: That's really interesting because now I'm starting to think, what if the elements in the collection were also a custom object? [chuckles] And then things could, I feel like, could be really powerful [laughs]. JOËL: There's often a lot of value, right? Because if the items in the collection are also a custom object, you can then have methods on them. And then, again, the sort of complexity of the reduce can sort of, like, fade away because it doesn't own any of the logic. All it does is saying, hey, there's a thing you can do to combine two items. Let's scale it up to work on a collection of items. And now you've sort of, like, really simplified what logic is actually owned inside the reduce. I do want to shout out for those listeners who are theory nerds and want to dig into this. When you have a reduce, and you've got an operation where all the values are of the same type, including the accumulator, typically, what you've got here is some form of monoid. It may be a semigroup. So, if you want to dig into some theory, those are the words to Google and to go a deep dive on. The main thing about monoids, in particular, is that monoids are any objects that have both a sort of a base case, a sort of empty version of themselves, and they have some sort of combining method that allows you to combine two values of that type. If your object has these things and follows...there's a few rules that have to be true. You have a monoid. And they can then be sort of guaranteed to be folded nicely because you can plug in their base case as your initial accumulator. And you can plug in their combining method as just the value of the block, and everything else just falls into place. A classic here is addition for numbers. So, if you want to add two numbers, your combining operator is a plus. And your sort of empty value is a zero. So, you would say, reduce initial value is zero, array of numbers. And your block is just plus, and it won't sum all of the numbers. You could do something similar with strings, where you can combine strings together with plus, and, you know, your empty string is your base case. So, now you're doing sort of string concatenation over arbitrary number of strings. Turns out there's a lot of operations that fall into that, and you can even define some of those on your custom object. So, you're like, oh, I've got a custom object. Maybe I want some way of, like, combining two of them together. You might be heading in the direction of doing something that is monoidal, and if so, that's a really good hint to know that it can sort of, like, just drop into place with a fold or a reduce and that that is a tool that you have available to you. STEPHANIE: Yeah, well, I think my eyes, like, widened a little bit when you first dropped the term monoid [laughs]. I do want to spend the last bit of our time talking about when not to use reduce, and, you know, we did talk a lot about recursion. But when do you think a regular old loop will just be enough? JOËL: So, you're suggesting when would you want to use something like an each rather than a reduce? STEPHANIE: Yeah. In my mind, you know, you did offer, like, a lot of ways to make reduce simpler, a lot of strategies to end up with some really nice-looking syntax [chuckles], I think. But, oftentimes, I think it can be equally as clear storing your accumulator outside of the iteration and that, like, is enough for me to understand. And reduce takes a little bit of extra overhead to figure out what I'm looking at. Do you have any thoughts about when you would prefer to do that? Or do you think that you would usually reach for something else? JOËL: Personally, I generally don't like the pattern of using each to iterate over a collection and then mutate some external accumulator. That, to me, is a bit of a code smell. It's a sign that each is not quite powerful enough to do the thing that I want to do and that I'm probably needing some sort of more specialized form of iteration. Sometimes, that's reduce. Oftentimes, because each can suffer from the same problem you mentioned from reduce, where it's like, oh, you're doing this thing where you mutate an external accumulator. Turns out what you're really doing is just map. So, use map or use select or, you know, some of the other built-in iterators from the enumerable library. There's a blog post on the thoughtbot blog that I continually link to people. And when I see the pattern of, like, mutating an external variable with each, yeah, I tend to see that as a bit of a code smell. I don't know that I would never do it, but whenever I see that, it's a sign to me to, like, pause and be like, wait a minute, is there a better way to do this? STEPHANIE: Yeah, that's fair. I like the idea that, like, if there's already a method available to you that is more specific to go with that. But I also think that sometimes I'd rather, like, come across that pattern of mutating a variable outside of the iteration over, like, someone trying to do something clever with the reduce. JOËL: Yeah, I guess reduce, especially if it's got, like, a giant block and you've got then, like, things in there that break or call next to skip iterations and things like that, that gets really mind-bending really quickly. I think a case where I might consider using an each over a reduce, and that's maybe generally when I tend to use each, is when I'm doing side effects. If I'm using a reduce, it's because I care about the accumulated value at the end. If I'm using each, it's typically because I am trying to do some amount of side effects. STEPHANIE: Yeah, that's a really good call out. I had that written down in my notes, and I'm glad you brought it up because I've seen them get conflated a little bit, and perhaps maybe that's the source of the pain that I'm talking about. But I really like that heuristic of reduce as, you know, you're caring about the output, as opposed to what's going on inside. Like, you don't want any unexpected behavior. JOËL: And I think that applies to something like map as well. My sort of heuristic is, if I'm doing side effects, I want each. If I want transformed values that are sort of one-to-one in the collection, I want map. If I want a single sort of aggregate value, then I want reduce. STEPHANIE: I think that's the cool thing about mixing paradigms sometimes, where all the strategies you talked about in terms of, you know, using custom, like, objects for your accumulator, or the elements in your collection, like, that's something that we get because, you know, we're using an object-oriented language like Ruby. But then, like, you also are kind of bringing the functional programming lens to, like, when you would use reduce in the first place. And yeah, I am just really excited now [chuckles] to start looking for some places I can use reduce after this conversation and see what comes out of it. JOËL: I think I went on a bit of an interesting journey where, as a newer programmer, reduce was just, like, really intense. And I struggled to understand it. And I was like, ban it from code. I don't want to ever see it. And then, I got into functional programming. I was like, I'm going to do reduce everywhere. And, honestly, it was kind of messy. And then I, like, went really deep on a lot of functional theory, and I think understood some things that then I was able to take back to my code and actually write reduce expressions that are much simpler so that now my heuristic is like, I love reduce; I want to use it, but I want as little as possible in the reduce itself. And because I understand some of these other concepts, I have the ability to know what things can be extracted in a way that will feel very natural, in a way that myself from five years ago would have just been like, oh, I don't know. I've got this, you know, 30-line reduce expression that I know is complicated, but I don't know how to improve. And so, a little bit of the underlying theory, I don't think it's necessary to understand these simplified reduces, but as an author who's writing them, I think it helps me write reduces that are simpler. So, that's been my journey using reduce. STEPHANIE: Yeah. Well, thanks for sharing. And I'm really excited. I hope our listeners have learned some new things about reduce and can look at it from a different light. JOËL: There are so many different perspectives. And I think we keep discovering new mental models as we talk to different people. It's like, oh, this particular perspective. And there's one that we didn't really dig into but that I think makes more sense in a functional world that's around sort of deconstructing a structure and then rebuilding it with different components. The shorthand name of this mental model, which is a fairly common one, is constructor replacement. For anyone who's interested in digging into that, we'll link it in the show notes. I gave a talk at an Elm meetup where I sort of dug into some of that theory, which is really interesting and kind of mind-blowing. Not as relevant, I think, for Rubyists, but if you're in a language that particularly allows you to build custom structures out of recursive types or what are sometimes called algebraic data types, or tagged unions, or discriminated unions, this thing goes by a bajillion names, that is a really interesting other mental model to look at. And, again, I don't think the list that we've covered today is exhaustive. You know, I would love it for any of our listeners; if you have your own mental models for how to think about folding, injecting, reducing, send them in: hosts@bikeshed.fm. We'd love to hear them. STEPHANIE: And on that note, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at: tbot.io/referral. Or you can email us at referrals@thoughtbot.com with any questions.
Stephanie shares about her vacation at Disney World, particularly emphasizing the technological advancements in the park's mobile app that made her visit remarkably frictionless. Joël had a conversation about a topic he loves: units of measure, and he got to go deep into the idea of dimensional analysis with someone this week. Together, Joël and Stephanie talk about module documentation within software development. Joël shares his recent experience writing module docs for a Ruby project using the YARD documentation system. He highlights the time-consuming nature of crafting good documentation for each public method in a class, emphasizing that while it's a demanding task, it significantly benefits those who will use the code in the future. They explore the attributes of good documentation, including providing code examples, explaining expected usage, suggesting alternatives, discussing edge cases, linking to external resources, and detailing inputs, outputs, and potential side effects. Multidimensional numbers episode (https://bikeshed.thoughtbot.com/416) YARD docs (https://yardoc.org/) New factory_bot documentation (https://thoughtbot.com/blog/new-docs-for-factory_bot) Dash (https://kapeli.com/dash) Solargraph (https://solargraph.org/) Transcript: JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. STEPHANIE: And I'm Stephanie Minn, and together, we're here to share a bit of what we've learned along the way. JOËL: So, Stephanie, what's new in your world? STEPHANIE: So, I recently was on vacation, and I'm excited [chuckles] to tell our listeners all about it. I went to Disney World [laughs]. And honestly, I was especially struck by the tech that they used there. As a person who works in tech, I always kind of have a little bit of a different experience knowing a bit more about software, I suppose, than just your regular person [laughs], citizen. And so, at Disney World, I was really impressed by how seamlessly the like, quote, unquote, "real life experience" integrated with their use of their branded app to pair with, like, your time at the theme park. JOËL: This is, like, an app that runs on your mobile device? STEPHANIE: Yeah, it's a mobile app. I haven't been to Disney in a really long time. I think the last time I went was just as a kid, like, this was, you know, pre-mobile phones. So, I recall when you get into the line at a ride, you can skip the line by getting what's called a fast pass. And so, you kind of take a ticket, and it tells you a designated time to come back so that you could get into the fast line, and you don't have to wait as long. And now all this stuff is on your mobile app, and I basically did not wait in [laughs] a single line for more than, like, five minutes to go on any of the rides I wanted. It just made a lot of sense that all these things that previously had more, like, physical touchstones, were made a bit more convenient. And I hesitate to use the word frictionless, but I would say that accurately describes the experience. JOËL: That's kind of amazing; the idea that you can use tech to make a place that's incredibly busy also feel seamless and where you don't have to wait in line. STEPHANIE: Yeah and, actually, I think the coolest part was it blended both your, like, physical experience really well with your digital one. I think that's kind of a gripe I have as a technologist [laughs] when I'm just kind of too immersed in my screen as opposed to the world around me. But I was really impressed by the way that they managed to make it, like, a really good supplement to your experience being there. JOËL: So, you're not hyped for a future world where you can visit Disney in VR? STEPHANIE: I mean, I just don't think it's the same. I rode a ride [laughs] where it was kind of like a mini roller coaster. It was called Expedition Everest. And there's a moment, this is, like, mostly indoors, but there's a moment where the roller coaster is going down outside, and you're getting that freefall, like, drop feeling in your stomach. And it also happened to be, like, drizzling that day that we were out there, and I could feel it, you know, like, pelting my head [laughs]. And until VR can replicate that experience [chuckles], I still think that going to Disney is pretty fun. JOËL: Amazing. STEPHANIE: So, Joël, what's new in your world? JOËL: I'm really excited because I had a conversation about a topic that I like to talk about: units of measure. And I got to go deep into the idea of dimensional analysis with someone this week. This is a technique where you can look at a calculation or a function and sort of spot-check whether it's correct by looking at whether the unit for the measure that would come out match what you would expect. So, you do math on the units and ignore the numbers coming into your formula. And, you know, let's say you're calculating the speed of something, and you get a distance and the amount of time it took you to take to go that distance. And let's say your method implements this as distance times time. Forget about doing the actual math with the numbers here; just look at the units and say, okay, we've got our meters, and we've got our seconds, and we're multiplying them together. The unit that comes out of this method is meters times seconds. You happen to know that speeds are not measured in meters times seconds. They're measured in meters divided by seconds or meters per second. So, immediately, you get a sense of, like, wait a minute, something's wrong here. I must have a bug in my function. STEPHANIE: Interesting. I'm curious how you're representing that data to, like, know if there's a bug or not. In my head, when you were talking about that, I'm like, oh yeah, I definitely recall doing, like, math problems for homework [laughs] where I had, you know, my meters per second. You have your little fractions written out, and then when you multiply or divide, you know how to, like, deal with the units on your piece of paper where you're showing your work. But I'm having a hard time imagining what that looks like as a programmer dealing with that problem. JOËL: You could do it just all in your head based off of maybe some comments that you might have or the name of the variable or something. So, you're like, okay, well, I have a distance in meters and a time in seconds, and I'm multiplying the two. Therefore, what should be coming out is a value that is in meters times seconds. If you want to get fancier, you can do things with value objects of different types. So, you say, okay, I have a distance, and I have a time. And so, now I have sort of a multiplication of a distance and a time, and sort of what is that coming out as? That can sometimes help you prevent from having some of these mistakes because you might have some kind of error that gets raised at runtime where it's like, hey, you're trying to multiply two units that shouldn't be multiplied, or whatever it is. You can also, in some languages, do this sort of thing automatically at the type level. So, instead of looking at it yourself and sort of inferring it all on your own based off of the written code, languages like F# have built-in unit-of-measure systems where once you sort of tag numbers as just being of a particular unit of measure, any time you do math with those numbers, it will then tag the result with whatever compound unit comes from that operation. So, you have meters, and you have seconds. You divide one by the other, and now the result gets tagged as meters per second. And then, if you have another calculation that takes the output of the first one and it comes in, you can tell the compiler via type signature, hey, the input for this method needs to be in meters per second. And if the other calculation sort of automatically builds something that's of a different unit, you'll get a compilation error. So, it's really cool what it can do. STEPHANIE: Yeah, that is really neat. I like all of those built-in guardrails, I suppose, to help you, you know, make sure that your answer is correct. Definitely could have used that [chuckles]. Turns out I just needed a calculator to take my math test with [laughs]. JOËL: I think what I find valuable more than sort of the very rigorous approach is the mindset. So, anytime you're dealing with numbers, thinking in your mind, what is the unit of this number? When I do math with it with a different number, is it the same unit? Is it a different unit? What is the unit of the thing that's coming out? Does this operation make sense in the domain of my application? Because it's easy to sometimes think you're doing a math operation that makes sense, and then when you look at the unit, you're like, wait a minute, this does not make sense. And I would go so far as to say that, you know, you might think, oh, I'm not doing a physics app. I don't care about units of measure. Most numbers in your app that are actually numbers are going to have some kind of unit of measure associated to them. Occasionally, you might have something where it's just, like, a straight-up, like, quantity or something like that. It's a dimensionless number. But most things will have some sort of unit. Maybe it's a number of dollars. Maybe it is an amount of time, a duration. It could be a distance. It could be all sorts of things. Typically, there is some sort of unit that should attach to it. STEPHANIE: Yeah. That makes sense that you would want to be careful about making sure that your mathematical operations that you're doing when you're doing objects make sense. And we did talk about this in the last episode about multidimensional numbers a little bit. And I suppose I appreciate you saying that because I think I have mostly benefited from other people having thought in that mindset before and encoding, like I mentioned, those guardrails. So, I can recall an app where I was working with, you know, some kind of currency or money object, and that error was raised when I would try to divide by zero because rather than kind of having to find out later with some, not a number or infinite [laughs] amount of money bug, it just didn't let me do that. And that wasn't something that I had really thought about, you know, I just hadn't considered that zero value edge case when I was working on whatever feature I was building. JOËL: Yeah, or even just generally the idea of dividing money. What does that even mean? Are you taking an amount of money and splitting it into two equivalent piles to split among multiple people? That kind of makes sense. Are you dividing money by another money value? That's now asking a very different kind of question. You're asking, like, what is the ratio between these two, I guess, piles of money if we want to make it, you know, in the physical world? Is that a thing that makes sense in your application? But also, realize that that ratio that you get back is not itself an amount of money. And so, there are some subtle bugs that can happen around that when you don't keep track of what your quantities are. So, this past week, I've been working on a project where I ended up having to write module docs for the code in question. This is a Ruby project, so I'm writing docs using the YARD documentation system, where you effectively just write code comments at the sort of high level covering the entire class and then, also, individual documentation comments on each of the methods. And that's been really interesting because I have done this in other languages, but I'd never done it in Ruby before. And this is a piece of code that was kind of gnarly and had been tricky for me to figure out. And I figured that a couple of these classes could really benefit from some more in-depth documentation. And I'm curious, in your experience, Stephanie, as someone who's writing code, using code from other people, and who I assume occasionally reads documentation, what are the things that you like to see in good sort of method-level docs? STEPHANIE: Personally, I'm really only reading method-level docs when, you know, at this point, I'm, like, reaching for a method. I want to figure out how to use it in my use case right now [laughs]. So, I'm going to search API documentation for it. And I really am just scanning for inputs, especially, I think, and maybe looking at, you know, some potential various, like, options or, like, variations of how to use the method. But I'm kind of just searching for that at a glance and then moving on [laughs] with my day. That is kind of my main interaction with module docs like that, and especially ones for Ruby and Rails methods. JOËL: And for clarity's sake, I think when we're talking about module docs here, I'm generally thinking of, like, any sort of documentation that sort of comments in code meant to document. It could be the whole modular class. It could be on a per-method level, things like RDoc or YARD docs on Ruby classes. You used the word API docs here. I think that's a pretty similar idea. STEPHANIE: I really haven't given the idea of writing this kind of documentation a lot of thought because I've never had to do too much of it before, but I know, recently, you have been diving deep into it because, you know, like you said, you found these classes that you were working with a bit ambiguous, I suppose, or just confusing. And I'm wondering what kind of came out of that journey. What are some of the most interesting aspects of doing this exercise? JOËL: And one of the big ones, and it's not a fun one, but it is time-consuming. Writing good docs per method for a couple of classes takes a lot of time, and I understand why people don't do it all the time. STEPHANIE: What kinds of things were you finding warranted that time? Like, you know, you had to, at some point, decide, like, whether or not you're going to document any particular method. And what were some of the things you were looking out for as good reasons to do it? JOËL: I was making the decisions to document or not document on a class level, and then every public method gets documentation. If there's a big public API, that means every single one of those methods is getting some documentation comments, explaining what they do, how they're meant to be used, things like that. I think my kind of conclusion, having worked with this, is that the sort of sweet spot for this sort of documentation is for anything that is library-like, so a lot of things that maybe would go into a Rails lib directory might make sense. Anything you're turning into a gem that probably makes sense. And sometimes you have things in your Rails codebase that are effectively kind of library-like, and that was the case for the code that I was dealing with. It was almost like a mini ORM style kind of ActiveRecord-inspired series of base classes that had a bunch of metaprogramming to allow you to write models that were backed by not a database but a headless CMS, a content management system. And so, these classes are not extracted to the lib directory or, like, made into a gem, but they feel very library-esque in that way. STEPHANIE: Library-like; I like that descriptor a lot because it immediately made me think of another example of a time when I've used or at least, like, consumed this type of documentation in a, like, SaaS repo. Rather, you know, I'm not really seeing that level of documentation around domain objects, but I noticed that they really did a lot of extending of the application record class because they just had some performance needs that they needed to write some, like, custom code to handle. And so, they ended up kind of writing a lot of their own ORM-like methods for just some, like, custom callbacks on persisting and some just, like, bulk insertion functionality. And those came with a lot of different ways to use them. And I really appreciated that they were heavily documented, kind of like you would expect those ActiveRecord methods to be as well. JOËL: So, I've been having some conversations with other members at thoughtbot about when they like to use the style of module doc. What are some of the alternatives? And one that kept coming up for different people that they would contrast with this is what they would call the big README approach, and this could be for a whole gem, or it could be maybe some directory with a few classes in your application that's got a README in the root of the directory. And instead of documenting each method, you just write a giant README trying to answer sort of all of the questions that you anticipate people will ask. Is that something that you've seen, and how do you feel about that as a tool when you're looking for help? STEPHANIE: Yes. I actually really like that style of documentation. I find that I just want examples to get me started, especially; I guess this is especially true for libraries that I'm not super familiar with but need to just get a working knowledge about kind of immediately. So, I like to see examples, the getting started, the just, like, here's what you need to know. And as I start to use them, that will get me rolling. But then, if I find I need more details, then I will try to seek out more specific information that might come in the form of class method documentation. But I'm actually thinking about how FactoryBot has one of the best big README-esque [laughs] style of documentation, and I think they did a really big refresh of the docs not too long ago. It has all that high-level stuff, and then it has more specific information on how to use, you know, the most common methods to construct your factories. But those are very detailed, and yet they do sit, like, separately from inline, like, code documentation in the style of module docs that we're talking about. So, it is kind of an interesting mix of both that I think is helpful for me personally when I want both the “what do I need to know now?” And the, “like, okay, I know where to look for if I need something a little more detailed.” JOËL: Yeah. The two don't need to be mutually exclusive. I thought it was interesting that you mentioned how much examples are valuable to you because...I don't know if this is controversial, but an opinion that I have about sort of per-method documentation is that you should always default to having a code example for every method. I don't care how simple it is or how obvious it is what it does. Show me a code example because, as a developer, examples are really, really helpful. And so, seeing that makes documentation a lot more valuable than just a couple of lines that explain something that was maybe already obvious from the title of the method. I want to see it in action. STEPHANIE: Interesting. Do you want to see it where the method definition is? JOËL: Yes. Because sometimes the method definition, like, the implementation, might be sort of complex. And so, just seeing a couple of examples, like, oh, you call with this input, you get that. Call with this other input; you get this other thing. And we see this in, you know, some of the core docs for things like the enumerable methods where having an example there to be like, oh, so that's how map works. It returns this thing under these circumstances. That sort of thing is really helpful. And then, I'll try to do it at a sort of a bigger level for that class itself. You have a whole paragraph about here's the purpose of the class. Here's how you should use it. And then, here's an example of how you might use it. Particularly, if this is some sort of, like, base class you're meant to inherit from, here's the circumstances you would want to subclass this, and then here's the methods you would likely want to override. And maybe here are the DSLs you might want to have and to kind of package that in, like, a little example of, in this case, if you wanted a model that read from the headless CMS, here's what an example of such a little model might look like. So, it's kind of that putting it all together, which I think is nice in the module docs. It could probably also live in the big README at some level. STEPHANIE: Yeah. As you are saying that, I also thought about how I usually go search for tests to find examples of usage, but I tend to get really overwhelmed when I see inline, like, that much inline documentation. I have to, like, either actively ignore it, choose to ignore it, or be like, okay, I'm reading this now [laughs]. Because it just takes up so much visual space, honestly. And I know you put a lot of work into it, a lot of time, but maybe it's because of the color of my editor theme where comments are just that, like, light gray [laughs]. I find them quite easy to just ignore. But I'm sure there will be some time where I'm like, okay, like, if I need them, I know they're there. JOËL: Yeah, that is, I think, a downside, right? It makes it harder to browse the code sometimes because maybe your entire screen is almost taken up by documentation, and then, you know, you have one method up, and you've got to, like, scroll through another page of documentation before you hit the next method, and that makes it harder to browse. And maybe that's something that plays into the idea of that separation between library-esque code versus application code. When you browse library-esque code, when you're actually browsing the source, you're probably doing it for different reasons than you would for code in your application because, at that point, you're effectively source diving, sometimes being like, oh, I know this class probably has a method that will do the thing I want. Where is it? Or you're like, there's an edge case I don't understand on this method. I wonder what it does. Let me look at the implementation. Or even some existing code in the app is using this library method. I don't know what it does, but they call this method, and I can't figure out why they're using it. Let me look at the source of the library and see what it does under the hood. STEPHANIE: Yeah. I like the distinction of it is kind of a different mindset that you're reading the code at, where, like, sometimes my brain is already ready to just read code and try to figure out inputs and outputs that way. And other times, I'm like, oh, like, I actually can't parse this right now [chuckles]. Like, I want to read just English, like, telling me what to expect or, like, what to look out for, especially when, like you said, I'm not really, like, trying to figure out some strange bug that would lead me to diving deep in the source code. It's I'm at the level where I'm just reaching for a method and wanting to use it. We're writing these YARD docs. I think I also heard you mention that you gave some, like, tips or maybe some gotchas about how to use certain methods. I'm curious why that couldn't have been captured in a more, like, self-documenting way. Or was there a way that you could have written the code for that not to have been needed as a comment or documented as that? And was there a way that method names could have been clear to signal, like, the intention that you were trying to convey through your documentation? JOËL: I'm a big fan of using method names as a form of documentation, but they're frequently not good enough. And I think comments, whether they're just regular inline comments or more official documentation, can be really good to help avoid sort of common pitfalls. And one that I was working with was, there were two methods, and one would find by a UID, so it would search up a document by UID. And another one would search by ID. And when I was attempting to use these before I even started documenting, I used the wrong one, and it took me a while to realize, oh wait, these things have both UIDs and IDs, and they're slightly different, and sometimes you want to use one or the other. The method names, you know, said like, "Find by ID" or "Find by UID." I didn't realize there were both at the time because I wasn't browsing the source. I was just seeing a place where someone had used it. And then, when I did find it in the source, I'm like, well, what is the difference? And so, something that I did when I wrote the docs was sort of call out on both of those methods; by the way, there is also find by UID. If you're searching by UID, consider using the other one. If you don't know what the difference is, here's a sentence summarizing the difference. And then, here's a link to external documentation if you want to dive into the nitty gritty of why there are two and what the differences are. And I think that's something you can't capture in just a method name. STEPHANIE: Yeah, that's true. I like that a lot. Another use case you can think of is when method names are aliased, and it's like, I don't know how I would have possibly known that until I, you know, go through the journey of realizing [laughs] that these two methods do the same thing or, like, stumbling upon where the aliasing happens. But if that were captured in, like, a little note when I'm in, like, a documentation viewer or something, it's just kind of, like, a little tidbit of knowledge [laughs] that I get to gain along the way that ends up, you know, being useful later because I will have just kind of...I will likely remember having seen something like that. And I can at least start my search with a little bit more context than when you don't know what you don't know. JOËL: I put a lot of those sorts of notes on different methods. A lot of them are probably based on a personal story where I made a mistaken assumption about this method, and then it burned me. But I'm like, okay, nobody else is going to make that mistake. By the way, if you think this is what the method does, it does something slightly different and, you know, here's why you need to know that. STEPHANIE: Yeah, you're just looking out for other devs. JOËL: And, you know, trying to, like, take my maybe negative experience and saying like, "How can I get value out of that?" Maybe it doesn't feel great that I lost an hour to something weird about a method. But now that I have spent that hour, can I get value out of it? Is the sort of perspective I try to have on that. So, you mentioned kind of offhand earlier the idea of a documentation viewer, which would be separate than just reading these, I guess, code comments directly in your code editor. What sort of documentation viewers do you like to use? STEPHANIE: I mostly search in my browser, you know, just the official documentation websites for Rails, at least. And then I know that there are also various options for Ruby as well. And I think I had mentioned it before but using DuckDuckGo as my search engine. I have nice bang commands that will just take me straight to the search for those websites, which is really nice. Though, I have paired with people before who used various, like, macOS applications to do something similar. I think Alfred might have some built-in workflows for that. And then, a former co-worker used to use one called Dash, that I have seen before, too. So, it's another one of those just handy just, like, search productivity extensions. JOËL: You mentioned the Rails documentation, and this is separate from the guides. But the actual Rails docs are generated from comments like this inline in code. So, all the different ActiveRecord methods, when you search on the Rails documentation you're like, oh yeah, how does find_by work? And they've got a whole, like, paragraph explaining how it works with a couple of examples. That's this kind of documentation. If you open up that particular file in the source code, you'll find the comments. And it makes sense for Rails because Rails is more of, you know, library-esque code. And you and I search these docs pretty frequently, although we don't tend to do it, like, by opening the Rails gem and, like, grepping through the source to find the code comment. We do it through either a documentation site that's been compiled from that source or that documentation that's been extracted into an offline tool, like you'd mentioned, Dash. STEPHANIE: Yeah, I realized how conflicting, I suppose, it is for me to say that I find inline documentation really overwhelming or visually distracting, whereas I recognize that the only reason I can have that nice, you know, viewing experience is because documentation viewers use the code comments in that format to be generated. JOËL: I wonder if there's like a sort of...I don't know what this pattern is called, but a bit of a, like, middle-quality trap where if you're going to source dive, like, you'd rather just look at the code and not have too much clutter from sort of mediocre comments. But if the documentation is really good and you have the tooling to read it, then you don't even need to source dive at all. You can just read the documentation, and that's sufficient. So, both extremes are good, but that sort of middle kind of one foot in each camp is sort of the worst of both worlds experience. Because I assume when you look for Rails documentation, you never open up the actual codebase to search. The documentation is good enough that you don't even need to look at the files with the comments and the code. STEPHANIE: Yeah, and I'm just recalling now there's, like, a UI feature to view the source from the documentation viewer page. JOËL: Yes. STEPHANIE: I use that actually quite a bit if the comments are a little bit sparse and I need just the code to supplement my understanding, and that is really nice. But you're right, like, I very rarely would be source diving, unless it's a last resort [laughs], let's be honest. JOËL: So, we've talked about documentation viewers and how that can make things nice, and you're able to read documentation for things. But a lot of other tooling can benefit from this sort of model documentation as well, and I'm thinking, in particular, Solargraph, which is Ruby's language server protocol. And it has plugins for VS Code, for Vim, for a few different editors, takes advantage of that to provide all sorts of things. So, you can get smart expansion of code and good suggestions. You can get documentation for what's under your cursor. Maybe you're reading somebody else's code that they've written, and you're like, why are they calling this parameterized method here? What does that even do? Like, in VS Code, you could just hover over it, and it will pop up and show you documentation, including the, like, inputs and return types, and things like that. That's pretty nifty. STEPHANIE: Yeah, that is cool. I use VS Code, but I've not seen that too much yet because I don't think I've worked in enough codebases with really comprehensive [laughs] YARD docs. I'm actually wondering, tooling-wise, did you use any helpful tools when you were writing them or were you hand-documenting each? JOËL: I was hand-documenting everything. STEPHANIE: Class. Okay. JOËL: The thing that I did use is the YARD gem, which you don't need to have the gem to write YARD-style documentation. But if you have the gem, you can run a local server and then preview a documentation site that is generated from your comments that has everything in there. And that was incredibly helpful for me as I was trying to sort of see an overview of, okay, what would someone who's looking at the docs generated from this see when they're trying to look for what the documentation of a particular method does? STEPHANIE: Yeah, and that's really nice. JOËL: Something that I am curious about that I've not really had a lot of experience with is whether or not having extra documentation like that can help AI tools give us better suggestions. STEPHANIE: Yeah, I don't know the answer to that either, but I would be really curious to know if that is already something that happens with something like Copilot. JOËL: Do better docs help machines, or are they for humans only? STEPHANIE: Whoa, that's a very [laughs] philosophical question, I think. It would make sense, though, that if we already have ways to parse and compile this kind of documentation, then I can see that incorporating them into the types of, like, generative problems that AI quote, unquote "solves" [chuckles] would be really interesting to find out. But anyone listening who kind of knows the answer to that or has experience working with AI tools and various types of code comment documentation would be really curious to know what your experience is like and if it improves your development workflow. So, for people who might be interested in getting better at documenting their code in the style of module docs, what would you say are some really great attributes of good documentation in this form? JOËL: I think, first of all, you have to write from the motivation of, like, if you were confused and wanting to better understand what a method does, what would you like to see? And I think coming from that perspective, and that was, in my case, I had been that person, and then I was like, okay, now that I've figured it out, I'm going to write it so that the next person is not confused. I have five or six things that I think were really valuable to add to the docs, a few of which we've already mentioned. But rapid fire, first of all, code example. I love code examples. I want a code example on every method. An explanation of expected usage. Here's what the method does. Here's how we expect you to use this method in any extra context about sort of intended use. Callouts for suggested alternatives. If there are methods that are similar, or there's maybe a sort of common mistake that you would reach for this method, put some sort of call out to say, "Hey, you probably came here trying to do X. If that's what you were actually trying to do, you should use method Y." Beyond that, a discussion of edge cases, so any sort of weird ways the method behaves. You know, when you pass nil to it, does it behave differently? If you call it in a different context, does it behave differently? I want to know that so that I'm not totally surprised. Links to external resources–really great if I want to, like, dig deeper. Is this method built on some sort of, like, algorithm that's documented elsewhere? Please link to that algorithm. Is this method integrating with some, like, third-party API? You know, they have some documentation that we could link to to go deeper into, like, what these search options do. Link to that. External links are great. I could probably find it by Googling myself, but you are going to make me very happy as a developer if you already give me the link. You'd mentioned capturing inputs and outputs. That's a great thing to scan for. Inputs and outputs, though, are more sometimes than just the arguments and return values. Although if we're talking about arguments, any sort of options hash, please document the keys that go in that because that's often not obvious from the code. And I've spent a lot of time source diving and jumping between methods trying to figure out like, what are the options I can pass to this hash? Beyond the explicit inputs and outputs, though, anything that is global state that you rely on. So, do you need to read something from an environment variable or even a global variable or something like that that might make this method behave differently in different situations? Please document that. Any situations where you might raise an error that I might not expect or that I might want to rescue from, let me know what are the potential errors that might get raised. And then, finally, any sorts of side effects. Does this method make a network call? Are you writing to the file system? I'd like to know that, and I'd have to, like, figure it out by trial and error. And sometimes, it will be obvious in just the description of the method, right? Oh, this method pulls data from a third-party API. That's pretty clear. But maybe it does some sort of, like, caching in the background or something to a file that's not really important. But maybe I'm trying to do a unit test that involves this, and now, all of a sudden, I have to do some weird stubbing. I'd like to know that upfront. So, those are kind of all the things I would love to have in my sort of ideal documentation comment that would make my life easier as a developer when trying to use some code. STEPHANIE: Wow. What a passionate plea [laughs]. I was very into listening to you list all of that. You got very animated. And it makes a lot of sense because I feel like these are kind of just the day-to-day developer issues we run into in our work and would be so awesome if, especially as the, you know, author where you have figured all of this stuff out, the author of a, you know, a method or a class, to just kind of tell us these things so we don't have to figure it out ourselves. I guess I also have to respond to that by saying, on one hand, I totally get, like, you want to be saved [chuckles] from those common pitfalls. But I think that part of our work is just going through that and playing around and exploring with the code in front of us, and we learn all of that along the way. And, ultimately, even if that is all provided to you, there is something about, like, going through it yourself that gives you a different perspective on it. And, I don't know, maybe it's just my bias against [laughs] all the inline text, but I've also seen a lot of that type of information captured at different levels of documentation. So, maybe it is a Confluence doc or in a wiki talking about, you know, common gotchas for this particular problem that they were trying to solve. And I think what's really cool is that, you know, everyone can kind of be served and that people have different needs that different styles of documentation can meet. So, for anyone diving deep in the source code, they can see all of those examples inline. But, for me, as a big Googler [laughs], I want to see just a nice, little web app to get me the information that I need to find. I'm happy having that a little bit more, like, extracted from my source code. JOËL: Right. You don't want to have to read the source code with all the comments in it. I think that's a fair criticism and, yeah, probably a downside of this. And I'm wondering, there might be some editor tooling that allows you to just collapse all comments and hide them if you wanted to focus on just the code. STEPHANIE: Yeah, someone, please build that for me. That's my passionate plea [laughs]. And on that note, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Bye. AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at: tbot.io/referral. Or you can email us at referrals@thoughtbot.com with any questions.
Joël discusses the challenges he encountered while optimizing slow SQL queries in a non-Rails application. Stephanie shares her experience with canary deploys in a Rails upgrade. Together, Stephanie and Joël address a listener's question about replacing the wkhtml2pdf tool, which is no longer maintained. The episode's main topic revolves around the concept of multidimensional numbers and their applications in software development. Joël introduces the idea of treating objects containing multiple numbers as single entities, using the example of 2D points in space to illustrate how custom classes can define mathematical operations like addition and subtraction for complex data types. They explore how this approach can simplify operations on data structures, such as inventories of T-shirt sizes, by treating them as mathematical objects. EXPLAIN ANALYZE visualizer (https://explain.dalibo.com/) Canary in a coal mine (https://en.wikipedia.org/wiki/Sentinel_species#Canaries) Episode 413: Developer Tales of Package Management (https://bikeshed.thoughtbot.com/413) Docs for media-specific CSS (https://developer.mozilla.org/en-US/docs/Web/CSS/@media) Episode 386: Value Objects Revisited: The Tally Edition (https://bikeshed.thoughtbot.com/386) Money gem (https://github.com/RubyMoney/money) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: I've recently been trying to do some performance enhancements to some very slow queries. This isn't a Rails app, so we're sort of combining together a bunch of different scopes. And the way they're composing together is turning out to be really slow. And I've reached for a tool that is just really fun. It's a visualizer for SQL query plans. You can put the SQL keywords in front of a query: 'EXPLAIN ANALYZE,' and it will then output a query plan, sort of how it's going to attempt to do the work. And that might be like, oh, we're going to use this index on this table to join on this other thing, and then we're going to...maybe this is a table that we think we're going to do a sequential scan through and, you know, it builds out a whole thing. It's a big block of text, and it's kind of intimidating to look at. So, there are a few websites out there that will do this. You just paste a query plan in, and they will build you a nice, little visualization, almost like a tree of, like, tasks to be done. Oftentimes, they'll also annotate it with metadata that they pulled from the query plan. So, oh, this particular node is the really expensive one because we're doing a sequential scan of this table that has 15 million rows in it. And so, it's really useful to then sort of pinpoint what are the areas that you could optimize. STEPHANIE: Nice. I have known that you could do that EXPLAIN ANALYZE on a SQL query, but I've never had to do it before. Is this your first time, or is it just your first time using the visualizer? JOËL: I've played around with EXPLAIN ANALYZE a little bit before. Pro tip: In Rails, if you've got a scope, you can just chain dot explain on the end, and instead of running the query, it will run the EXPLAIN version of it and return the query plan. So, you don't need to, like, turn into SQL then manually run it in your database system to get the EXPLAIN. You can just tack a dot explain on there to get the query plan. It's still kind of intimidating, especially if you've got a really complex query that's...this thing might be 50 lines long of EXPLAIN with all this indentation and other stuff. So, putting it into a sort of online visualizer was really helpful for the work that I was doing. So, it was my first time using an online visualizer. There are a few out there. I'll link to the one that I used in the show notes. But I would do that again, would recommend. STEPHANIE: Nice. JOËL: So, Stephanie, what's new in your world? STEPHANIE: So, I actually just stepped away from being in the middle of doing a Rails upgrade [chuckles] and releasing it to production just a few minutes before getting on to record with you on this podcast. And the reason I was able to do that, you know, without feeling like I had to just monitor to see how it was going is because I'm on a project where the client is using canary deploys. And I was so pleasantly surprised by how easy it made this experience where we had decided to send the canary release earlier this morning. And the way that they have it set up is that the canary goes to 10% of traffic. 10% of the users were on Rails 7 for their sessions. And we saw a couple of errors in our error monitoring service. And we are like, "Okay, like, let's take a look at this, see what's going on." And it turns out it was not too big of a deal because it had to do with, like, a specific page. And, for the most part, if a user did encounter this error, they probably wouldn't again after refreshing because they had, like, a 90% chance [chuckles] of being directed to the previous version where everything is working. And we were kind of making that trade-off of like, oh, we could hotfix this right now on the canary release. But then, as we were starting to debug a little bit, it was a bit hairier than we expected originally. And so, you know, I said, "I have to hop on to go record The Bike Shed. So, why don't we just take this canary down just for the time being to take that time pressure off? And it's Friday, so we're heading into the weekend. And maybe we can revisit the issue with some fresh eyes." So, I'm feeling really good, actually. And I'm glad that we were able to do something that seems scary, but there were guardrails in place to make it a lot more chill. JOËL: Yay for the ability to roll back. You used the term canary release. That's not one that I'm familiar with. Can you explain what a canary release is? STEPHANIE: Oh yeah. Have you heard of the phrase 'Canary in the coal mine'? JOËL: I have. STEPHANIE: Okay. So, I believe it's the same idea where you are, in this case, releasing a potentially risky change, but you don't want to immediately make it available to, like, all of your users. And so, you send this change to, like, a small reach, I suppose, and give it a little bit of a test and see [chuckles] what comes back. And that can help inform you of any issues or risks that might happen before kind of committing to deploying a potentially risky change with a bigger impact. JOËL: Is this handled with something like a feature flag framework? Or is this, like, at an infrastructure level where you're just like, "Hey, we've got the canary image in, like, one container on one server, and then we'll redirect 10% of traffic to that to be served by that one and the other 90% to be served by the old container or something like that"? STEPHANIE: Yeah, in this case, it was at the infrastructure level. And I have also seen something similar at a feature flag level, too, where you're able to have some more granularity around what percent of users are seeing a feature. But I think with something like a Rails upgrade, it was nice to be able to have that at that infrastructure level. It's not necessarily, like, a particular page or feature to show or not show. JOËL: Yeah, I think you would probably want that at a higher level when you're changing over the entire app. Is this something that you had to custom-build yourself or something that just sort of came out of the box with some of the infrastructure tools you're using? STEPHANIE: It came out of the box, actually. I just joined this client project this week and was very delighted to see just some really great deployment infrastructure and getting to meet the DevOps engineers, too, who built it. And they're really proud of it. They kind of walked us through our first release earlier this week. And he was telling me, the DevOps engineer, that this was actually his favorite part of the job, is walking people through their first release and being their buddy while they do it. Because I think he gets to also see users interact with the tool that he built, and he had a lot of pride in that, so it was a very delightful experience. JOËL: That's so wonderful. I've been on so many projects where the sort of infrastructure side of things is not the team's strong point, and releasing can be really scary. And it's great to hear the opposite of that. We recently received a question for Stephanie based on an earlier episode. So, the question asks, "In episode 413, Stephanie discussed a recent issue she encountered with wkhtml2pdf. The episode turned into a deeper discussion about package management, but I don't think it ever cycled back to the conclusion. I'm curious: how did Stephanie solve this dilemma? We're facing the same issue on a project that my team maintains. It's an old codebase, and there are bits of old code that use wkhtml2pdf to generate print views of our data in our application. The situation is fairly dire. wkhtml2pdf is no longer maintained. In fact, it won't even be available to install from our operating system's package repositories in June. We're on FreeBSD, but I assume the same will be eventually true for other operating systems. And so, unless you want to maintain some build step to check out and compile the source code for an application that will no longer receive security updates, just living with it isn't really an option. There are three options we're considering. One, eliminate the dependency entirely. Based on user feedback, it sounds like our old developers were using this library to generate PDFs when what users really wanted was an easy way to print. So, instead of downloading a PDF, just ensure the screen has a good print style sheet and register an onload handler to call window dot print. We're thinking we could implement this as an A/B test to the feature to test this theory. Or two, replace wkhtml2pdf with a call to Headless Chrome and use that to generate the PDF. Or, three, replace wkhtml2pdf with a language-level package. For us, that might be the dompdf library available via Composer because we're a PHP shop." Yeah, a lot to unpack here. Any high-level thoughts, Stephanie? STEPHANIE: My first thought while I was listening to you read that question is that wkhtml2pdf is such a mouthful [laughs]. And I was impressed how you managed to say it at least, like, five times. JOËL: So, I try to say that five times fast. STEPHANIE: And then, my second high-level thought was, I'm so sorry to Brian, our listener who wrote in, because I did not really solve this dilemma [chuckles] for my project and team. I kind of kicked the can down the road, and that's because this was during a support and maintenance rotation that I've talked a little bit about before on the show. I was only working on this project for about a week. And what we thought was a small bug to figure out why PDFs were a little bit broken turned out, as you mentioned, to be this kind of big, dire dilemma where I did not feel like I had enough information to make a good call about what to do. So, I kind of just shared my findings that, like, hey, there is kind of a risk and hoping that someone else [laughs] would be able to make a better determination. But I really was struck by the options that you were considering because it was actually a bit of a similar situation to the bug I was sharing where the PDF that was being generated that was slightly broken. I don't think it was, like, super valuable to our users that it be in the form of a PDF. It really was just a way for them to print something to have on handy as a reference from, you know, some data that was generated from the app. So, yeah, based on what you're sharing, I feel really excited about the first one. Joël, I'm sure you have some opinions about this as well. JOËL: I love sort of the bigger picture thinking that Brian is doing here, sort of stepping back and being like, wait, why do we even need PDF here, and how are our customers using it? I think those are the really good questions to ask before sinking a ton of time into coming up with something that might be, like, a bit of a technical wonder. Like, hey, we managed to, like, do this PDF generation thing that we had to, like, cobble together so many other things. And it's so cool technically, but does it actually solve the underlying problem? So, shout out to Brian for thinking about it in those terms. I love that. Second cool thing that I wanted to shout out, because I think this is a feature of browsers that not many people are aware of; you can have multiple style sheets for your page, and you can tag them to be for different media. So, you can have a style sheet that only gets applied when you print versus when you display on screen. And there are a couple of others. I don't remember exactly what they are. I'll link to the docs in the show notes. But taking advantage of this, like, this is old technology but making that available and saying, "Yeah, we'll make it so that it's nice when you print, and we'll maybe even, you know, a link or a button with JavaScript so that you could just Command-P or Control-P to print. But we'll have a button in there as well that will allow you to print to PDF," and that solves your problem right there. STEPHANIE: Yeah, that's really cool. I didn't know that about being able to tag style sheets for different media types. That's really fascinating. And I like that, yeah, we're just eliminating this dependency on something, like, potentially really complex with a, hopefully, kind of elegant and modern solution, maybe. JOËL: And your browser is already able to do so many of these things. Why do we sort of try to recreate it? Printing is a thing browsers have been able to do for a long time. Printing to PDF is a thing that you can do for a long time. I will sometimes use that on sites where I need to, let's say I'm purchasing something, and I need some sort of receipt to expense, but they won't give me a download, a PDF download that I can send to the accounting team, so I will print to PDF the, like, HTML view. And that works just fine. It's kind of a workaround hack. Sometimes, it doesn't work well because the HTML page is just not well set up to, like, show up on a PDF page. You get some, like, weird, like, pagination issues or things like that. But, you know, just a little bit of thought for a print style sheet, especially for something you know that people are likely going to want to print or to save to PDF, that's a nice touch. STEPHANIE: Yeah. So, good luck, Brian, and let us know how this goes and any outcomes you find successful. So, for today's longer topic, I was excited because I saw, Joël, you dropped something in our topic backlog: Multidimensional Numbers. I'm curious what prompted this idea and what you wanted to say about it. JOËL: We did an episode a while back where we talked about value objects, wrapping numbers, wrapping collections. This is Episode 386, and we were talking about tallying, specifically working with collections of T-shirt sizes and doing math on these sort of objects that might contain multiple numbers. And a sort of sidebar from that that we didn't really get into is the idea that objects that contain sort of multiple numbers can be treated as a number themselves. And I think a great example of this is something like a point in two-dimensional space. It's got an x coordinate, a y coordinate. It's two numbers, but you can treat sort of the combination of the two of them together as a single number. There's a whole set of coordinate math that you can do to do things like add coordinates together, subtract them, find the distance between them. There's a whole field of vector math that we can do on those. And I think learning to recognize that numbers are not just instances of the integer or the float class but that there could be these more complex things that are also numbers is maybe an important realization and something that, as developers, if we think of these sort of more complex values as numbers, or at least mathematical objects, then that will help us write better code. STEPHANIE: Cool. Yeah. When you were first talking about 2D points, I was thinking about if I have experience working with that before or, like, having to build something really heavily based off of, like, a canvas or, you know, a coordinate system. And I couldn't think of any really good examples until I thought about, like, geographic locations. JOËL: Oh yeah, like a latitude, longitude. STEPHANIE: Yeah, exactly. Like, that is a lot more common, I think, for various types of just, like, production applications than 2D points if you're not working on, like, a video game or something like that, I think. JOËL: Right, right. I think you're much more likely to be working with 2D points on some more sort of front-end-heavy application. I was talking with someone this week about managing a seat map for concerts and events like that and sort of creating a seat map and have it be really interactive, and you can, like, click on seats and things like that. And depending on the level of libraries you're using to build that, you may have to do a lot of 2D math to make it all come together. STEPHANIE: Yeah. So, I would love to get into, you know, maybe we've realized, okay, we have some kind of compound number. What are some good reasons for using them differently than you would a primitive? JOËL: So, you mentioned primitives, and I think this is where maybe I'm developing a reputation about, like, always wanting value objects for everything. But it would be really easy, let's say, for an xy point to be just an array of two numbers or maybe even a hash with an x key and a y key. What's tricky about that is that then you don't have the ability to do math on them. Arrays do define the plus operator, but they don't do what you want them to do with points. It's the set union. So, adding two points would not at all do what you want, or subtracting two points. So, instead, if you have a custom 2D point class and you can define plus and minus on there to do the right thing, now they're not pairs of numbers, two values; they're a single value, and you can treat them as if they are just a single number. STEPHANIE: You mentioned that arrays don't do the right thing when you try to add them up. What is the right thing that you're thinking of then? JOËL: It probably depends a little bit on the type of object you're working with. So, with 2D points, you're probably trying to do vector addition where you're effectively saying almost, like, "Shift this point in 2D space by the amount of this other point." Or if you're doing a subtraction, you might even be asking, like, "What is the distance between these two points?" Euclidean distance, I think, is the technical term for this. There's also a couple of different ways you can multiply values. You can multiply a 2D point by just a sort of, not by another point, but by just an integer. That's called scaling. So, you're just like, oh, take this point in 2D space, but make it bigger, make it five times bigger or five times further from the origin. Or you can do some stuff with other points. But what you don't want to do is turn this into, if you're starting with arrays, you don't want to turn this into an array of four points. When you add two points in 2D space, you're not trying to create a point in 4D space. STEPHANIE: Whoa, I mean [laughs], maybe you're not. JOËL: You could but -- [laughter] STEPHANIE: Yeah. While you were saying that, I guess that is what is really cool about wrapping, encapsulating them in objects is that you get to decide what that means for you and your application, and -- JOËL: Yeah. Well, plus can mean different things, right? STEPHANIE: Yeah. JOËL: On arrays, plus means combining two arrays together. On integers, it means you do integer math. And on points, it might be vector addition. STEPHANIE: Are there any other arithmetic operators you can think of that would be useful to implement if you were trying to create some functionality on a point? JOËL: That's a good question because I think realizing the inverse of that is also a really powerful thing. Just because you create a sort of new mathematical object, a point in 2D space, doesn't mean that necessarily every arithmetic operator makes sense on it. Does it make sense to divide a point by another point? Maybe not. And so, instead of going with the mindset of, oh, a point is a mathematical object, I now need to implement all of arithmetic on this, instead, think in terms of your domain. What are the operations that make sense? What are the operations you need for this point? And, you know, maybe the answer is look up what are the common sort of vector math operations and implement those on your 2D point. Some of them will map to arithmetic operators like plus and minus, and then some of them might just be some sort of custom method where maybe you say, "Oh, I want the Euclidean distance between these two points." That's just a thing. Maybe it's just a named instance method on there. But yeah, don't feel like you need to implement all of the math operators because that's a mistake that I have made and then have ended up, like, implementing nonsensical things. STEPHANIE: [laughs] Creating your own math. JOËL: Yes, creating my own math. I've done this even on where I've done value objects to wrap single values. I was doing a class to represent currency, and I was like, well, clearly, you need, like, methods to, like, add or subtract your currency, and that's another thing. If you have, let's say, a plus method, now you can plug it into, let's say, reduce plus. And you can just sum a list of these currency objects and get back a new currency. It's not even going to give you back an integer. You just get a sort of new currency object that is the sum of all the other ones, and that's really nice. STEPHANIE: Yeah, that's really cool. It reminds me of all the magic of enumerable that you had talked about in a previous conference talk, where, you know, you just get so much out of implementing those basic operators that, like, kind of scales in handiness. JOËL: Yes. Turns out Ruby is actually a pretty nice system. If you have objects that respond to some common methods and you plug them into enumerable, and it just all kind of works. STEPHANIE: So, one thing you had said earlier that I've felt kind of excited about and wanted to highlight was you mentioned all the different ways that you could represent a 2D point with more primitive data stores, so, you know, an array of two integers, a hash with xy keys. It got me thinking about how, yeah, like, maybe if your system has to talk to another system and you're importing data or exporting data, it might eventually need to take those forms. But what is cool about having an encapsulated object in your application is you can kind of control those boundaries a little bit and have more confidence in terms of the data types that you're using within your system by having various ways to construct that, like, domain object, even if the data coming in is in a different shape. JOËL: And I think that you're hitting on one of the real beauties of object-oriented programming, where the sort of users of your object don't need to know about the internal representation. Maybe you store an array internally. Maybe it's two separate instance variables. Maybe it's something else entirely. But all that the users of your, let's say, 2D point object really need to care about is, hey, the constructor wants values in this shape, and then I can call these domain methods on it, and then the rest just sort of happens. It's an implementation detail. It doesn't matter. And you alluded, I think, to the idea that you can sort of create multiple constructors. You called them constructors. I tend to call them that as well. But they're really just class methods that will kind of, like, add some sugar on top of the constructor. So, you might have, like, a from array pair or from hash or something like that that allows you to maybe do a little bit of massaging of the data before you pass it into your constructor that might want some underlying form. And I think that's a pattern that's really nice. STEPHANIE: Yeah, I agree. JOËL: Something that can be interesting there, too, is that mathematically, there are multiple ways you can think of a 2D point. An xy coordinate pair is a common one, but another sort of system for representing a point in 2D space is called the polar coordinate system. So, you have some sort of, like, origin point. You're 0,0. And then, instead of saying so many to the left and so many up from that origin point, you give an angle and a distance, and that's where your point is. So, an angle and distance point, I think, you know, theta and magnitude are the fancy terms for this. You could, instead of creating a separate, like, oh, I have a polar coordinate point and a Cartesian coordinate point, and those are separate things, you can say, no, I just have a point in 2D space. They can be constructed from either an xy coordinate pair or a magnitude angle pair. Internally, maybe you convert one to the other for internal representation because it makes the math easier or whatever. Your users never need to know that. They just pass in the values that they want, use the constructor that is most convenient for them, and it might be both. Maybe some parts of the app require polar coordinates; some require Cartesian coordinates. You could even construct one of each, and now you can do math with each other because they're just instances of the same class. STEPHANIE: Whoa. Yeah, I was trying to think about transforming between the two types as well. It's all possible [laughs]. JOËL: Yes. Because you could have reader-type methods on your object that say, oh, for this point, give me its x coordinate; give me its y coordinate. Give me its distance from the origin. Give me its angle from the origin. And those are all questions you can ask that object, and it can calculate them. And you don't need to care what its internal representation is to be able to get all four of those. So, we've been talking about a lot of these sort of composite numbers, not composite numbers, that's a separate mathematical thing, but numbers that are composed of sort of multiple sub-numbers. And what about situations where you have two things, and one of them is not a number? I'm thinking of all sorts of units of measure. So, I don't just have three. I have three, maybe...and we were talking about currency earlier, so maybe three U.S. dollars. Or I don't just have five; I have five, you know, let's say, meters of distance. Would you consider something like that to be one of these compound number things? STEPHANIE: Right. I think I was–when we were originally talking about this, conflating the two. But I realized that, you know, just because we're adding context to a number and potentially packaging it as a value object, it's still different from what we're talking about today where, you know, there's multiple components to the number that are integral or required for it to mean what we intended to mean, if that makes sense. JOËL: Yeah. STEPHANIE: So yeah, I guess we did want to kind of make a distinction between value objects that while the additional context is important and you can implement a lot of different functionality based on what it represents, at the end of the day, it only kind of has one magnitude or, like, one integer to kind of encapsulate it represented as a number. Does that sound right? JOËL: Yeah. You did throw out the words encapsulation and value object. So, in a situation maybe where I have three US dollars, would you create some kind of custom object to wrap that? Or is that a situation where you'd be more comfortable using some kind of primitive? Like, I don't know, maybe an array pair of three and the symbol USD or something like that. STEPHANIE: Oh, I would definitely not do that [laughter]. Yeah. Like I, you know, for the most part, I think I've seen that as a currency object, and that expands the world of what we can do with it, converting into a lot of different other currencies. And yeah, just making sure those things don't get divorced from each other because that context is what gives it meaning. But when it comes to our compound numbers, it's like, without all of the components, it doesn't make sense, or it doesn't even represent the same, like, numerical value that we were trying to convey. JOËL: Right. You need both, or, you know, it could be more than two. It could be three, four, or five numbers together to mean something. You mentioned conversions, which I think is something that's also interesting because a lot of units of measure have sort of multiple ways of measuring, and you often want to convert between them. And maybe that's another case where encapsulation is really nice where, you know, maybe you have a distance object. And you have five meters, and you put that into your distance object, but then somebody wants it in feet somewhere else or in centimeters, or something like that. And it can just do all the conversion math safely inside that object, and the user doesn't have to worry about it. STEPHANIE: Right. This is maybe a bit of a tangent, but as a Canadian living in the U.S., I don't know [laughs] if you have any opinions about converting meters and feet. JOËL: The one I actually do the most often is converting Celsius to Fahrenheit and vice versa. You know, I've been here, what, 11 years now? I don't have a great intuition for Fahrenheit temperatures. So, I'm converting in my head just [laughs] on a daily basis. STEPHANIE: Yeah, that makes sense. Conversions: they're important. They help out our friends who [laughs] are on different systems of measurement. JOËL: There's a classic story that I love about unit conversions. I think it's one of the NASA Mars missions. STEPHANIE: Oh yeah. JOËL: You've heard of this one. It was trying to land on Mars, and it burned up in the atmosphere because two different teams had been building different components and used different unit systems, both according to spec for their own module. But then, when the modules try to talk to each other, they're sending over numbers in meters instead of feet or something like that. And it just caused [laughs] this, like, multi-year, multi-billion dollar project to just burn up. STEPHANIE: That's right. So, lesson of the day is don't do that. I can think of another example where there might be a little bit of misconceptions in terms of how to represent it. And I'm thinking about time and when that has been represented in multiple parts, such as in hours and, minutes and seconds. Do you have any initial impressions about a piece of data like that? JOËL: So, that's really interesting, right? Because, at first glance, it looks like, oh, it's, like, a triplet of hour, minute, seconds. It's sort of another one of these sort of compound numbers, and I guess you could implement it that way. But in reality, you're tracking a single quantity, the amount of time elapsed, and that can be represented with a single number. So, if you're representing, let's say, time of day, what would show up on your clock? That could be, depending on the resolution, number of, let's say, seconds since midnight, and that's a single counter. And then, you can do some math on it to get hours, minutes, seconds for a particular moment. But really, it's a single quantity, and we can do that with time. We can't do that with a 2D point. Like, it has to have two components. STEPHANIE: So, do you have a recommendation for what unit of time time would best be stored? I'm just thinking of all the times that I've had to do that millisecond, you know, that conversion of, you know, however many thousands of milliseconds in my head into something that actually means [laughs] something to me as a human being who measures time in hours and minutes. JOËL: My recommendation is absolutely go for a single number that you store in your, let's say, time of day object. It makes the math so much easier. You don't have to worry about, like, overflowing from one number into another when you're doing math or anything like that. And then the number that you count should be at the whatever the smallest resolution you care at. So, is there ever any time where you want to distinguish between two different milliseconds in time? Or maybe you're like, you know what? These are, like, we're tracking time of day for appointments. We don't care about the difference between two milliseconds. We don't need to track them independently. We don't even care about seconds. The most granular we ever care about things is by the minute. And so, maybe then your internal number that you track is a counter of minutes since midnight. But if you need more precision, you can go down to seconds or milliseconds or nanoseconds. But yeah, find what is the sort of the least resolution you want to get away with and then make that the unit of measure for a single counter in your object. And then encapsulate that so that nobody else needs to care that, internally, your time of day object is doing milliseconds because nobody wants to do that math. Just give me a nice, like, hours and minutes method on your object, and I will use that. I don't need to know internally what it's using. Please don't just pass around integers; wrap it in an object, especially because integers, there's enough times where you're doing seconds versus milliseconds. And when I just have an integer, I never know if the person storing this integer means seconds or milliseconds. So, I'm just like, oh, I'm going to pass to this, like, user object, a, like, time integer. And unless there's a comment or a constant, you know, that's named something duration in milliseconds or something like that, you know, or sometimes even, like, one year in milliseconds, or there's no way of knowing. STEPHANIE: Yeah. That makes a lot of sense. When you kind of choose a standard of a standard unit, it's, like, possible to make it easier [laughs]. JOËL: So, circling back to sort of the initial thing that sparked this conversation, the previous episode about T-shirt inventories, there we were dealing with what started off as, like, a hash of different T-shirt sizes and quantities of T-shirts that we had in that size, so small (five), medium (three), large (four). And then, we eventually turned that into a value object that represented...I think we called it a tally, but maybe we called it inventory. And this may be wrong, so tell me if I'm wrong here, I think we can kind of treat that as a number, as, like, one of these compound numbers. It's a sort of multidimensional number where you say, well, we have sort of three dimensions where we can have numbers that sort of increase and decrease independently. We can do math on these because we can take inventories or tallies and add and subtract them. And that's what we ended up having to do. We created a value object. We implemented plus and minus on it. There are rules for how the math works. I think this is a multidimensional number with the definition we're working on this show. Am I wrong here? STEPHANIE: I wouldn't say that you're wrong. I think I would have to think a little [laughs] more to say definitively that you're right. But I know that this example came from, you know, an application I was actually working on. And one of the main things that we had to do with these representations [laughs], I'm hesitant to call them a number, especially, but we had to compare these representations frequently because an inventory, for example, in a warehouse, wanting to make sure that it is equal to or there's enough of the inventory if someone was placing an order, which would also contain, like, a representation of T-shirt size inventory. And that was kind of where some of that math happened because, you know, maybe we don't want to let someone place an order if the inventory at the warehouse is smaller than their order, right? So, there is something really compelling about the comparison operations that we were doing that kind of is leaning me in the direction of, like, yeah, like, it makes sense to me to use this in a way that I would compare, like, quantities or numbers of something. JOËL: I think one thing that was really compelling to me, and that kind of blew my mind, was that we were trying to, like, figure out some things like, oh, we've got so many people with these size preferences, and we've got so many T-shirts across different warehouses. And we're summing them up and we're trying to say like, "How many do we need to purchase if there is a deficit?" And we can come up with effectively a formula for this. We're like, sum these numbers, when we're talking about just before we introduce sizes when it's just like, oh, people have T-shirts. They all get the count of people and a count of T-shirts in our warehouse, and we find, you know, the difference between that. And there's a few extra math operations we do. Then you introduce size, and you break it down by, oh, we've got so many of each. And now the whole thing gets really kind of messy and complicated. And you're doing these reduces and everything. When we start treating the tally of T-shirts as an object, and now it's a number that responds to plus and minus, all of a sudden, you can just plug those back into the original formula, and it all just works. The original formula doesn't care whether the numbers you're doing this formula on are simple integers or these sort of multidimensional numbers. And that blew my mind, and it was so cool. STEPHANIE: Yeah, that is really neat. And you get a lot of added benefits, too. I think the other important piece in the T-shirt size example was kind of tracking the state change, and that's so much easier when you have an object. There's just a lot more you can do with it. And even if, you know, you're not persisting every single version of the representation, you know, because sometimes you don't want to, sometimes you're really just kind of only holding it in memory to figure out if you need to, you know, do something else. But other times, you do want to persist it. And it just plugs in really well with, like, the rest of object-oriented programming [laughs] in terms of interacting with the rest of your business needs, I think, in your app. JOËL: Yeah, turns out objects, they're kind of nice. And you can do math with them. Who knew? Math is not just about integers. STEPHANIE: And on that note, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeee!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at: tbot.io/referral. Or you can email us at referrals@thoughtbot.com with any questions.
Stephanie has a delightful and cute Ruby thing to share: Honeybadger, the error monitoring service, has created exceptionalcreatures.com, where they've illustrated and characterized various common Ruby errors into little monsters, and they're adorable. Meanwhile, Joël encourages folks to submit proposals for RailsConf. Together, Stephanie and Joël delve into the nuances of adapting to and working within new codebases, akin to aligning with a shared mental model or vision. They ponder several vital questions that every developer faces when encountering a new project: the balance between exploring a codebase to understand its structure and diving straight into tasks, the decision-making process behind adopting new patterns versus adhering to established ones, and the strategies teams can employ to assist developers who are familiarizing themselves with a new environment. Honeybadger's Exceptional Creatures (https://www.exceptionalcreatures.com/) RailsConf CFP coaching sessions (https://docs.google.com/forms/d/e/1FAIpQLScZxDFaHZg8ncQaOiq5tjX0IXvYmQrTfjzpKaM_Bnj5HHaNdw/viewform) HTTP Cats (https://http.cat/) Support and Maintenance Episode (https://bikeshed.thoughtbot.com/409) Transcript: JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. STEPHANIE: And I'm Stephanie Minn. And together, we're here to share a bit of what we've learned along the way. JOËL: So, Stephanie, what's new in your world? STEPHANIE: I have a delightful and cute Ruby thing to share I'd seen just in our internal company Slack. Honeybadger, the error monitoring service, has created a cute little webpage called exceptionalcreatures.com, where they've basically illustrated and characterized various common Ruby errors into little monsters [laughs], and I find them adorable. I think their goal is also to make it a really helpful resource for people encountering these kinds of errors, learning about them for the first time, and figuring how to triage or debug them. And I just think it's a really cool way of, like, making it super approachable, debugging and, you know, when you first encounter a scary error message, can be really overwhelming, and then Googling about it can also be equally [chuckles] overwhelming. So, I just really liked the whimsy that they kind of injected into something that could be really hard to learn about. Like, there are so many different error messages in Ruby and in Rails and whatever other libraries you're using. And so, that's kind of a...I think they've created a one-stop shop for, you know, figuring out how to move forward with common errors. And I also like that it's a bit of a collective effort. They're calling it, like, a bestiary for all the little creatures [laughs] that they've discovered. And I think you can, like, submit your own favorite Ruby error and any guidance you might have for someone trying to debug it. JOËL: That's adorable. It reminds me a little bit of HTTP status codes as cat memes site. It has that same energy. One thing that I think is really interesting is that because it's Honeybadger, they have stats on, like, frequency of these errors, and a lot of these ones are tied to...I think they're picking some of the most commonly surfaced errors. STEPHANIE: Yeah, there's little, like, ratings, too, for how frequently they occur, kind of just like, I don't know, Pokémon [laughs] [inaudible 02:31]. I think it's really neat that they're using something like a learning from their business or maybe even some, like, proprietary information and sharing it with the world so that we can learn from it. JOËL: I think one thing that's worth specifying as well is that these are specific exception classes that get raised. So, they're not just, like, random error strings that you see in the wild. They don't often have a whole lot of documentation around them, so it's nice to see a dedicated page for each and a little bit of maybe how this is used in the real world versus maybe how they were designed to be used. Maybe there's a line or two in the docs about, you know, core Ruby when a NoMethodError should be raised. How does NoMethodError actually get used, you know, in real life, and the exceptions that Honeybadger is capturing. That's really interesting to see. STEPHANIE: Yeah, I like how each page for the exception class, and I'm glad you made that distinction, is kind of, like, crowdsourced guidance and information from the community, so I think you could even, you know, contribute to it if you wanted. But yeah, just a fun, little website to bring you some delight when you're on your next head-smacking, debugging adventure [laughs]. JOËL: And I love that it brings some joy to the topic, but, honestly, I think it's a pretty good reference. I could see myself linking to this anytime I want to have a deeper discussion on exceptions. So, maybe there's a code review, and maybe I want to suggest that we raise a different error than the one that we're doing. I could see myself in that GitHub comment being like, "Oh, instead of, you know, raising an exception here, why don't we instead raise a NoMethodError or something like that?" And then link to the bestiary page. STEPHANIE: So, Joël, what's new in your world? JOËL: So, just recently, RailsConf announced their call for proposals. It's a fairly short period this year, only about three-ish weeks long. So, I've been really encouraging colleagues to submit and trying to be a resource for people who are interested in speaking at conferences. We did a Q&A session with a fellow thoughtboter, Aji Slater, who's also a former RailsConf speaker, about what makes for a good talk, what is it like to submit to a call for proposals, you know, kind of everything from the process from having an idea all the way to stage presence and delivering. And there's a lot of great questions that got asked and some good discussion that happened there. STEPHANIE: Nice. Yeah, I think I have noticed that you are doing a lot more to help, especially first-time speakers give their first conference talk this year. And I'm wondering if there's anything you've learned or any hopes and dreams you have for kind of the amount of time you're investing into supporting others. JOËL: What I'd like to see is a lot of people submitting proposals; that's always a great thing. And, a proposal, even if it doesn't get accepted, is a thing that you can resubmit. And so, having gone through the effort of building a proposal and especially getting it maybe peer-reviewed by some colleagues to polish your idea, I think is already just a really great exercise, and it's one that you can shop around. It's one that you can maybe convert into a blog post if you need to. You can convert that into some kind of podcast appearance. So, I think it's a great way to take an idea you're excited about and focus it, even if you can't get into RailsConf. STEPHANIE: I really like that metric for success. It reminds me of a writer friend I have who actually was a guest on the show, Nicole Zhu. She submits a lot of short stories to magazines and applications to writing fellowships, and she celebrates every rejection. I think at the end of the year, she, like, celebrates herself for having received, you know, like, 15 rejections or something that year because that meant that she just went for it and, you know, did the hard part of doing the work, putting yourself out there. And that is just as important, you know, if not more than whatever achievement or goal or the idea of having something accepted. JOËL: Yeah, I have to admit; rejection hurts. It's not a fun thing to go through. But I think even if you sort of make it to that final stage of having written a proposal and it gets rejected, you get a lot of value out of that journey sort of regardless of whether you get accepted or not. So, I encourage more people to do that. To any of our listeners who are interested, the RailsConf call for proposals goes through February 13th, 2024. So, if you are listening before then and are inspired, I recommend submitting. If you're unsure of what makes for a good CFP, RailsConf is currently offering coaching sessions to help craft better proposals. They have one on February 5th, one on February 6th, and one on February 7th, so those are also options to look into if this is maybe your first time and you're not sure. There's a signup form. We'll link to it in the show notes. STEPHANIE: So, another update I have that I'm excited to get into for the rest of the episode is my recent work on our support and maintenance team, which I've talked about on the show before. But for any listeners who don't know, it's a kind of sub-team at thoughtbot that is focused on helping maintain multiple client projects at a time. But, at this point, you know, there's not as much active feature development, but the work is focused on keeping the codebase up to date, making any dependency upgrades, fixing any bugs that come up, and general support. So, clients have a team to kind of address those things as they come up. And when I had last talked about it on the podcast, I was really excited because it was a bit of a different way of working. I felt like it was very novel to be, you know, have a lot of different projects and domains to be getting into. And knowing that I was working on this team, like, short-term and, you know, it may not be me in the future continuing what I might have started during my rotation, I thought it was really interesting to be optimizing towards, like, completion of a task. And that had kind of changed my workflow a bit and my process. JOËL: So, now that you've been doing work on the support and maintenance team for a while and you've kind of maybe gotten more comfortable with it, how are you generally feeling about this idea of sort of jumping into new codebases all the time? STEPHANIE: It is both fun and more challenging than I thought it would be. I tend to actually really enjoy that period of joining a new team or a project and exploring, you know, a codebase and getting up to speed, and that's something that we do a lot as consultants. But I think I started to realize that it's a bit of a tricky balance to figure out how much time should I be spending understanding what this codebase is doing? Like, how much of the application do I need to be understanding, and how much poking around should I be doing before just trying to get started on my first task, the first starter ticket that I'm given? There's a bit of a balance there because, on one hand, you could just immediately start on the task and kind of just, you know, have your blinders [chuckles] on and not really care too much about what the rest of the code is doing outside of the change that you're trying to make. But that also means that you don't have that context of why certain things are the way they are. Maybe, like, the way that you want to be building something actually won't work because of some unexpected complexity with the app. So, I think there, you know, needs to be time spent digging around a little bit, but then you could also be digging around for a long time [chuckles] before you feel like, okay, I finally have enough understanding of this new codebase to, like, build a feature exactly how a seasoned developer on the team might. JOËL: I imagine that probably varies a little bit based on the task that you're doing. So, something like, oh, we want to upgrade this codebase to Ruby 3.3, probably requires you to have a very different understanding of the codebase than there's a bug where submitting a comment double posts it, and you have to dig into that. Both of those require you to understand the application on very different levels and kind of understand different mental models of what the app is doing. STEPHANIE: Yeah, absolutely. That's a really good point that it can depend on what you are first asked to work on. And, in fact, I actually think that is a good guidepost for where you should be looking because you could develop a mental model that is just completely unrelated [chuckles] to what you're asked to do. And so, I suppose that is, you know, usually a good place to start, at least is like, okay, I have this first task, and there's some understanding and acceptance that, like, the more you work on this codebase, the more you'll explore and discover other parts of it, and that can be on a need to know kind of basis. JOËL: So, I'm thinking that if you are doing something like a Ruby upgrade or even a Rails upgrade, a lot of what you care about the app is going to be on a more mechanical level. So, you want to know what gems you're using. You want to know what different patterns are being used, maybe how callbacks are happening, any particular features that are version-specific that are being used, things like that. Whereas if you're, you know, say, fixing a bug, you might care a lot more about some of the product-level concerns. What are we actually trying to do here? What is the expected user experience? How does this deviate from that? What were the underlying mental models of the developers? So, there's almost, like, two lenses you can look at the code. Now, I almost want to make this a two-dimensional thing, where you can look at it either from, like, a very kind of mechanical lens or a product lens in one axis. And then, on the other axis, you could look at it from a very high-level 10,000-foot view and maybe zoom in a little bit where you need, versus a very localized view; here's where the bug is happening on this page, and then sort of zoom out as necessary. And I could see different sorts of tasks falling in different quadrants there of, do I need a more mechanical view? Do I need a more product-focused view? And do I need to be looking locally versus globally? STEPHANIE: Wow. I can't believe you just created a Cartesian graph [laughs] for this problem on the fly. But I love it because I do think that actually lines up with different strategies I've taken before. It's like, how much do you even look at the code before deciding that you can't really get a good picture of it, of what the product is, without just poking around from the app itself? I actually think that I tend to start from the code. Like, maybe I'll see a screenshot that someone has shared of the app, you know, like a bug or something that they want me to fix, and then looking for that text in the code first, and then trying to kind of follow that path, whereas it's also, you know, perfectly viable to try to see the app being used in production, or staging, or something first to get a better understanding of some of the business problems it's trying to solve. JOËL: When you jump into a new codebase, do you sort of consciously take the time to plan your approach or sort of think about, like, how much knowledge of this new codebase do I need before I can, like, actually look at the problem at hand? STEPHANIE: Ooh, that's kind of a hard question to answer because I think my experience has told me enough times that it's never what I think it's going to [laughs] be, not never, but it frequently surprises me. It has surprised me enough times that it's kind of hard to know off the bat because it's not...as much as we work in frameworks that have opinions and conventions, a lot of the work that happens is understanding how this particular codebase and team does things and then having to maybe shift or adjust from there. So, I think I don't do a lot of planning. I don't really have an idea about how much time it'll take me because I can't really know until I dive in a little bit. So, that is usually my first instinct, even if someone is wanting to, like, talk to me about an approach or be, like, "Hey, like, how long do you think this might take based on your experience as a consultant?" This is my first task. Oftentimes, I really can't say until I've had a little bit of downtime to, in some ways, like, acquire the knowledge [chuckles] to figure that out or answer that question. JOËL: How much knowledge do you like to get upfront about an app before you dive into actually doing the task at hand? Are there any things, like, when you get access to a new codebase, that you'll always want to look at to get a sense of the project before you look at any tickets? STEPHANIE: I actually start at the model level. Usually, I am curious about what kinds of objects we're working with. In fact, I think that is really helpful for me. They're like building blocks, in order for me to, like, conceptually understand this world that's being represented by a codebase. And I kind of either go outwards or inwards from there. Usually, if there's a model that is, like, calling to me as like, oh, I'll probably need to interact with, then I'll go and seek out, like, where that model is created, maybe through controllers, maybe through background jobs, or something like that, and start to piece together entry points into the application. I find that helpful because a lot of the times, it can be hard to know whether certain pages or routes are even used at all anymore. They could just be dead code and could be a bit misleading. I've certainly been misled [chuckles] more than once. And so, I think if I'm able to pull out the main domain objects that I notice in a ticket or just hear people talk about on the team, that's usually where I gravitate towards first. What about you? Do you have a place you like to start when it comes to exploring a new codebase like that? JOËL: The routes file is always a good sort of overview of, like, what is going on in the app. Scanning the models directory is also a great start in a Rails app to get a sense of what is this app about? What are the core nouns in our vocabulary? Another thing that's good to look for in a codebase is what are the big types of patterns that they tend to use? The Rails ecosystem goes through fads, and, over time, different patterns will be more popular than others. And so, it's often useful to see, oh, is this an app where everything happens in service objects, or is this an app that likes to rely on view components to render their views? Things like that. Once you get a sense of that, you get a little bit of a better sense of how things are architected beyond just the basic MVC. STEPHANIE: I like that you mentioned fads because I think I can definitely tell, you know, how modern an app is or kind of where it might be stuck in time [chuckles] a little bit based on those patterns and libraries that it's heavily utilizing, which I actually find to be an interesting and kind of challenging position to be in because how do you approach making changes to a codebase that is using a lot of patterns or styles from back in the day? Would you continue following those same patterns, or do you feel motivated to introduce something new or kind of what might be trendy now? JOËL: This is the boring answer, but it's almost never worth it to, like, rewrite the codebase just to use a new pattern. Just introducing the new pattern in some of the new things means there are now two patterns. That's also not a great outcome for the team. So, without some other compelling reason, I default to using the established patterns. STEPHANIE: Even if it's something you don't like? JOËL: Yes. I'm not a huge fan of service objects, but I work in plenty of codebases that have them, and so where it makes sense, I will use service objects there. Service objects are not mutually exclusive with other things, and so sometimes it might make sense to say, look, I don't feel like I can justify a service object here. I'll do this logic in a view, or maybe I'll pull this out into some other object that's not a service object and that can live alongside nicely. But I'm not necessarily introducing a new pattern. I'm just deciding that this particular extraction might not necessarily need a service object. STEPHANIE: That's an interesting way to describe it, not as a pattern, but as kind of, like, choosing not to use the existing [chuckles] pattern. But that doesn't mean, like, totally shifting the architecture or even how you're asking other people to understand the codebase. And I think I'm in agreement. I'm actually a bit of a follower, too, [laughs], where I want to, I don't know, just make things match a little bit with what's already been created, follow that style. That becomes pretty important to me when integrating with a team in a codebase. But I actually think that, you know, when you are calibrating to a codebase, you're in a position where you don't have all that baggage and history about how things need to be. And maybe you might be empowered to have a little bit more freedom to question existing patterns or bring some new ideas to the team to, hopefully, like, help the code evolve. I think that's something that I struggle with sometimes is feeling compelled to follow what came before me and also wanting to introduce some new things just to see what the team might think about them. JOËL: A lot of that can vary depending on what is the pattern you want to introduce and sort of what your role is going to be on that team. But that is something that's nice about someone new coming onto a project. They haven't just sort of accepted that things are the way they are, especially for things that the team already doesn't like but doesn't feel like they have the energy to do anything better about it. So, maybe you're in a codebase where there's a ton of Ruby code in your ERB templates, and it's not really a pattern that you're following. It's just a thing that's there. It's been sort of the path of least resistance for a long time, and it's easier to add more lines in there, but nobody likes it. New person joins the team, and their naive exuberance is just like, "We can fix it. We can make it better." And maybe that's, you know, going back and rewriting all of your views. That's probably not the best use of their time. But it could be maybe the first time they have to touch one of these views, cleaning up that one and starting a conversation among the team. "Hey, here are some patterns that we might like to clean up some of these views instead," or "Here are maybe some guidelines for anything new that we write that we want to do to keep our views clean," and sort of start moving the needle in a positive direction. STEPHANIE: I like the idea of moving the needle. Even though I tend to not want to stir the pot with any big changes, one thing that I do find myself doing is in a couple of places in the specs, just trying to refactor a bit away from using lets. There were some kind of forward-thinking decisions made before when RSpec was basically going to deprecate using the describe block without prepending it with their module, so just kind of throwing that in there whenever I would touch a spec and asking other people to do the same. And then, recently, one kind of, like, small syntax thing that I hadn't seen before, and maybe this is just because of the age of the codebases in which I'm working, the argument forwarding syntax in Ruby that has been new, I mean, it's like not totally new anymore [laughs], but throwing that in there a little every now and then to just kind of shift away from this, you know, dated version of the code kind of towards things that other people are seeing and in newer projects. JOËL: I love harnessing that energy of being new on a project and wanting to make things better. How do you avoid just being, you know, that developer, though, that's new, comes in, and just wants to change everything for the sake of change or for your own personal opinions and just kind of moves things around, stirs the pot, but doesn't really contribute anything net positive to the team? Because I've definitely seen that as well, and that's not a good first contribution or, you know, contribution in general as a newer team member. How do we avoid being that person while still capitalizing on that energy of being someone new and wanting to make a positive impact? STEPHANIE: Yeah, that's a great point, and I kind of alluded to this earlier when I asked, like, oh, like, even if you don't like an existing syntax or pattern you'll still follow it? And I think liking something a different way is not a good enough reason [chuckles]. But if you are able to have a good reason, like I mentioned with the RSpec prepending, you know, it didn't need to happen now, but if we would hope to upgrade that gem eventually, then yeah, that was a good reason to make that change as opposed to just purely aesthetic [laughs]. JOËL: That's one where there is pretty much a single right answer to. If you plan to keep staying up to date with versions of RSpec, you will eventually need to do all these code changes because, you know, they're deprecating the old way. Getting ahead of that gradually as we touch spec files, there's kind of no downside to it. STEPHANIE: That's true, though maybe there is a person who exists out there who's like, "I love this old version of RSpec, and I will die on this hill that we have to stay on [laughs] it." But I also think that I have preferences, but I'm not so attached to them. Ideally, you know, what I would love to receive is just, like, curiosity about like, "Oh, like, why did you make this change?" And just kind of share my reasoning. And sometimes in that process, I realize, you know, I don't have a great reason, and I'll just say, "I don't have a great reason. This is just the way I like it. But if it doesn't work for you, like, tell me, and I'll consider changing it back. [chuckles]" JOËL: Maybe that's where there's a lot of benefit is the sort of curiosity on the part of the existing team and sort of openness to both learn about existing practices but also share about different practices from the new teammate. And maybe that's you're coming in, and you have a different style where you like to write tests, maybe without using RSpec's let syntax; the team is using it. Maybe you can have a conversation with the team. It's almost certainly not worth it for you to go and rewrite the entire test suite to not use let and be like, "Hey, first PR. I made your test better." STEPHANIE: Hundreds of files changed, thousands [laughs] of lines of code. I think that's actually a good segue into the question of how can a team support a new hire or a new developer who is still calibrating to a codebase? I think I'm curious about this being different from onboarding because, you know, there are a lot of things that we already kind of expect to give some extra time and leeway for someone who's new coming in. But what might be some ways to support a new developer that are less well known? JOËL: One that I really like is getting them involved as early as possible in code review because then they get to see the patterns that are coming in, and they can be involved in conversations on those. The first PR you're reviewing, and you see a bunch of tests leaning heavily on let, and maybe you ask a question, "Is this a pattern that we're following in this codebase? Did we have a particular motivation for why we chose this?" And, you know, and you don't want to do it in a sort of, like, passive-aggressive way because you're trying to push something else. It has to come from a place of genuine curiosity, but you're allowing the new teammate to both see a lot of the existing patterns kind of in very quick succession because you see a pretty good cross-section of those when you review code. And also, to have conversations about them, to ask anything like, "Oh, that's unusual. I didn't know we were doing that." Or, "Hey, is this a pattern that we're doing kind of just local to this subsystem, or is this something that's happening all the way? Is this a pattern that we're using and liking? Is this a thing that we were doing five years ago that we're phasing out, but there's still a few of them left?" Those are all, I think, great questions to ask when you're getting started. STEPHANIE: That makes a lot of sense. It's different from saying, "This is how we do things here," and expecting them to adapt or, you know, change to fit into that style or culture, and being open to letting it evolve based on the new team, the new people on the team and what they might be bringing to the table. I like to ask the question, "What do you need to know?" Or "What do you need to be successful?" as opposed to telling them what I think they need [laughs]. I think that is something that I actually kind of recently, not regret exactly, but I was kind of helping out some folks who were going to be joining the team and just trying to, like, shove all this information down their throats and be like, "Oh, and watch out for these gotchas. And this app uses a lot of callbacks, and they're really complex." And I think I was maybe coloring their [chuckles] experience a little bit and expecting them to be able to drink from the fire hose, as opposed to trusting that they can see for themselves, you know, like, what is going on, and form opinions about it, and ask questions that will support them in whatever they are looking to do. When we talked earlier about the four different quadrants, like, the kind of information they need to know will differ based off of their task, based off of their experience. So, that's one way that I am thinking about to, like, make space for a new developer to help shape that culture, rather than insisting that things are the way they are. JOËL: It can be a fine balance where you want to be open to change while also you have to remain kind of ruthlessly pragmatic about the fact that change can be expensive. And so, a lot of changes you need to be justified, and you don't want to just be rewriting your patterns for every new employee or, you know, just to follow the latest trends because we've seen a lot of trends come and go in the Rails ecosystem, and getting on all of them is just not worth our time. STEPHANIE: And that's the hard truth of there's always trade-offs [laughs] in software development, isn't that right? JOËL: It sure is. You can't always chase the newest shiny, as fun as that is. STEPHANIE: On that note, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at: tbot.io/referral. Or you can email us at referrals@thoughtbot.com with any questions.
Joël shares his recent experience with Turbo, a JavaScript framework that simplifies adding interactivity to websites without extensive JavaScript coding. Stephanie gives an update on her quest to work from her office more, and the birds have arrived—most notably, chickadees. Stephanie and Joël address a listener question from Edward about the concept of a "spike" in software development. They discuss the nature of spikes, emphasizing that they are typically throwaway work aimed at learning and de-risking rather than producing final code, and explore how spikes can lead to better decision-making and prioritization in software development, especially in complex codebases. Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: I'm pretty excited because this week, I actually got to use a little bit of Turbo for the first time. Turbo is Rails'...I guess it's not technically just for Rails. It's a sort of unobtrusive JavaScript framework that allows you to build a lot of interactive functionality without actually having to write a lot of JavaScript yourself, just by writing some HTML in a certain way. And you can add a lot of functionality and interactivity to your site without having to drop to custom writing some JavaScript. STEPHANIE: Cool. Yeah, that is exciting. I personally have not gotten to use too much of it in a production/client setting; only played around with it a little bit on my own to keep up with what's new and just kind of reading about how other people are excited to use it. So, what are your first impressions so far? JOËL: It's pretty nice. It, you know, works as advertised. My situation, I was rendering a calendar view of a lot of events, and this is completely server-rendered. And I realized, wait a minute, there are some days where I've got, like, 20 events, and I really, like, I want my calendar squares to say sort of equally sized. So, I wanted to limit myself to only showing four or five events per calendar day. And so, I added a little link at the bottom of the calendar day that says, you know, "See more." And when you click that link, it does some Turbo stuff, and it pulls in other events so that you can now sort of expand it to get the whole day. So, it's just a little bit of interactivity that you kind of get for free with Turbo just by wrapping a particular HTML tag around it and having the Turbo library loaded. STEPHANIE: That's cool. I'm excited to try it out next time I'm working on a Rails project that just needs a little bit of that interactivity, you know, just to make that experience a little bit richer. And it seems like a really good, like, low-effort way to add some of those enhancements. Based on what you described, it sounds really easy. JOËL: Yeah, I was impressed with just how low effort it all was, which is what you want, right? It works out of the box. So, for anyone who's kind of curious about it, Turbo Frames is the little bit that I used, and it worked really well. Oh, something I'm actually excited about it as well; it plays nicely with clients that have disabled JavaScript. So, this link that I click to pull in the rest of the events, if somebody has JavaScript disabled, or if they command-click or control-click to open in a new tab, it doesn't just do nothing like it would often do in many sort of front-end framework-y places that have hijacked the URL click handler. Instead, it actually opens up the full list of items in a new page, just as if you'd clicked a normal link. So, it really gives you that progressive enhancement feel where I can click a link, and it goes to another page with a list of all the 30 events if I don't have JavaScript. But if I do, maybe I get a slightly better experience where, instead of taking me to a new page, it just expands the list, and I get to see the full list. So, it plays nicely on both sides. STEPHANIE: That's really cool. As someone who's just starting to dabble in some alternative browsers outside of the main popular ones [chuckles], I have noticed how many websites do not work for me anymore [laughs]. And that sounds, like, nice from a user perspective. JOËL: So, other than dabbling with the new browsers, what's new in your world? STEPHANIE: A few weeks ago, I talked about [laughs] sitting more at my desk and, you know, various incentives that I gave myself to do that. And I'd like to say that I've been doing a pretty good job [laughs]. So, what's new in my world is that I've followed up on my commitment to sit at my desk more, feel a little bit more organized in my workday. And that's especially true because the birds have finally discovered my bird feeder [laughs]. JOËL: Oh, that's really cool. STEPHANIE: There were a few weeks where I was not really getting any visitors, and, you know, I was just like, when are they going to come and eat this delicious birdseed that I've [laughs] put out for them? And it seems like a flock of chickadees that normally like to hang out on the apple tree in my backyard have figured out this new source of food, and they'll sometimes, five of them at a time, will come, and sometimes they even fight [laughs] to get on the ledge to hang out at the bird feeder. And yeah, it turns out that the six pounds of bird feed that I bought, I'll start to turn through [laughs] that a little bit quicker now, so I'm excited about that and just to also see other birds and species come and go as time goes on. So, that's been an exciting new development. JOËL: So, the six pounds of birdseed might not last you through the winter. STEPHANIE: I was debating between six pounds and, like, a 20-pound bag [laughs], which that would have been a lot. And so far, I think the six pounds has been serving me well. We'll see how long it lasts, but yeah, it's finally starting. I might have to refill it soon, so, you know, I was hopefully not going to have to store all that bird feed [laughs] just, like, in my house for a long time. JOËL: Any birds that have shown up that have been particularly fun to watch or that are maybe your favorites? STEPHANIE: I mentioned the chickadees because they seem to come as a group, and I really like watching them interact with each other. It's just kind of like bird TV, you know, it's not just a single bird. It's just watching these animals that are a collective do their thing. And I've been enjoying that a lot. JOËL: Now I'm just imagining a reality TV but the Chickadee edition. STEPHANIE: Oh yeah, definitely. I know some people put, like, cameras at their bird feeders to either live stream, which is funny because most of the time, there's nothing happening [laughs]. Usually, the birds are really in and out. Or they'll have, like, a really fancy camera to take, like, really beautiful up-close photos. There's a blog that I discovered recently where someone posts about the birds that visit them at their place in Michigan. I'll link to it in the show notes, but it's really cool to see these, like, up-close and personal photos of basically the bird's mouth. Sometimes, they're open [laughs], so you can see right in them. I don't know; maybe there's a time where I'll get so into it that I'll create my own bird feeder blog. JOËL: Well, if you do, you should definitely share it with the listeners on the podcast. Speaking of listeners on the podcast, we've recently had a listener question from Edward that I thought was a really interesting topic, and I wanted to take a whole episode to dig into. And Edward asks about the concept of a spike. Sometimes, we're asked to investigate a complex new feature, and you might want to do some evaluation on the feasibility and complexity and build out just enough of it to make a well-informed opinion. And ideally, you're doing that in a way that reduces risk of spending too much time with unproven impact. The problem is that in any reasonably complex codebase, that investigation work can be most of the work needed to build the feature. And Edward gives an example: if you're adding a system admin role, the core of the work is adding a new role with all of the abilities, but the real work is ensuring that it interacts with the entire system in the appropriate way. So, how do you manage making sure that you're doing spikes well? And Edward asks if this is something that we've experienced a sort of feeling that we're doing 90% of the work in the spike. He also asks, does this say something about the codebase that you're working on? If it's hard to spike in it, does that say something about the underlying codebase, or are we just all doing spikes wrong? So yeah, I'm curious, Stephanie: do you occasionally spike things out in code on your projects? STEPHANIE: Yeah, I do. I think one piece that was left a little bit unsaid is that I think spiking usually comes up when the team can't really estimate how long a task will take, you know, assuming that you use estimates on your team [chuckles]. That calls for a spike ticket, right? And someone will spend some time. And I think on some teams, this is usually time-boxed as well to maybe do a proof of concept or, yeah, do some of that initial exploration. JOËL: Before we go too deep, I think it's probably useful to define spike in that I think it's a little bit easy and probably varies from team to team and even from a developer to developer. I think, for me, when I think of a spike, it's throwaway work. The code that I write will not get shipped, and this is not code that will just get improved later. It is entirely throwaway work. And the purpose of it is to learn something about the project that's being done. Typically, it's in a sort of de-risking fashion, so to say, look, we've got a feature that's got a lot of unknowns in it. And if we commit to it right now or we start investing time into it, it could become a bit of a time pit. Let's try to answer some questions about it. Let's try to resolve some of those unknowns so that we can better make decisions around maybe estimation, but maybe even just prioritization. If this seems like something that would be really challenging to do, maybe we don't want to prioritize it this quarter. Is that similar to how you think of spikes, or do you have a different sort of definition of it? STEPHANIE: Yeah, I am glad you mentioned that it's throwaway work. I think I was a little hesitant to commit to that definition with conviction because even based off of what Edward was saying, there's kind of, like, maybe different ideas about that or different expectations. But I sometimes think that, depending, spiking doesn't even necessarily need to lead to code. Like, it could just be answering questions. And so, at the same time, I think it is, I like what you said, work that helps you learn more about the system, whether or not there's some code written as, like, a potential path at the end of it. JOËL: Interesting. So, you would put some things that don't involve code at all in the spike bucket. STEPHANIE: I think there have been times where I've done a spike, and I've not coded out anything, but I've answered some questions, and I've left comments about unearthing some of the uncertainty that led us to want to explore the idea in the first place. Then, again, I also have gone down the path of, like, trying out a solution and maybe even multiple and then evaluating afterwards which ones I think were more suitable. So, it could mean both. I think that is actually something that's within the power of whoever is assigned this work to determine whatever is valuable to them in order to get enough information to figure out how you want to move forward. JOËL: Another element of spikes that I think is often implied is that because this is throwaway work, you're not necessarily putting in all the work to make everything sort of clean, or well-structured, or reusable, or anything like that. So, it's quite possible that you would not even test this. You might not break this out into objects in the way that you would if this had to be reused. You might have duplication all over, and that's okay because the purpose of this code is not to be sort of production-grade; it's to answer some questions, and then you're going to throw it away and, using those answers, build something correctly. STEPHANIE: Yeah, I think that's true. And it's kind of an interesting distinction from, you know, what you might consider your regular work in which the expectation is that it will be shipped [chuckles]. And there's also some amount of conflating the two, I think because if, you know, you and I are saying like, yeah, like, this exploration should be standalone, and it is not going to be used to be built on top of necessarily, there is some amount of revisiting. And you're not starting from scratch because you have an idea, but you are starting fresh if you will. And so, you know, when you are doing that spiking, I think it allows you to move a little bit faster, but that doesn't mean that the work is, like, any X percent [laughs] done at the end of it. JOËL: The work is still kind of, I guess, 0% done, again, because this is throwaway code, in our definition of a spike anyway. Would you distinguish between the terms spike and prototype? STEPHANIE: Oh, interesting. My initial reaction is that a prototype would then be user-tested [laughs] in some way. Like, the point is to then show someone and then get them interacting with it, any initial reactions from that. Whereas a spike is really for the developer and maybe the team to discuss. JOËL: I like that distinction. I definitely think that a spike, for me, is purely technical. We're not spiking out a feature by putting a thing live in production behind a feature flag, showing it to 10% of users, and seeing how they respond to that. That's not a spike. So, I think something a little bit more like that, or where you're showing things maybe to users, or you're wanting to do maybe some user testing with something. And it can be throwaway code still. I think now you're starting to get something more that you would call a prototype. So, I like that distinction of, is this sort of internal or external? But in the way they're used, they can often be similar, and that oftentimes both will sort of...they're built to be as cheap as possible to answer the questions you're trying to get answered, whether that's from a user or just technical reasons. And so, the whole thing can be a little bit of smoke and mirrors, a little bit of duct tape and toothpicks, as long as you only have...like, the only solid parts you need are the parts that are going to help you answer your question. And so, any hack or cheat you can get to to bypass everything else is time you've saved, and that's a good thing. STEPHANIE: Oh, I'm very curious about this idea of time saved because I think sometimes an underappreciated outcome of a spike is what not to do or is choosing not to do something. And it can feel not great to have spent hours or even days exploring a path just to realize that it's not worth it. I'm curious, like, when you know to stop and also, how you get other people kind of onboard that even just figuring out an initial idea was not a viable solution, how that could be a valuable insight to the rest of the team. JOËL: Something that I think can be really useful is before you even start spiking out something, write a list of questions that you're trying to answer with this code, and then don't let yourself get distracted. Write the minimum amount of code that will allow you to answer those questions. So, maybe that is a question around, is it possible to connect this external API to our systems? There are some questions around, like, how credentials and things will work or how complex that will be. It might be a question around, like, maybe there's even, like, a performance thing. We want to talk to an external system and, you know, the responses back need to be within a certain amount of time. Otherwise, this whole approach where we're going to try to fetch data live is not feasible. So, the answer we need there is, can we do it live, or do we need to consider some sort of background fetching, or caching approach, or something like that? So, write the minimum amount of code that it would take to do that. And maybe the minimum amount of code, like you said, is not even really code. Maybe it's a script or even just trying out some curl commands and timing them at the command line. It could be a lot of things. But I think having a list of questions up front really helps you focus on the purpose of the spike. And I think it helps me a little bit as well with emotional attachment in that success is not necessarily coming to a yes on all of those questions. It is having an answer, going from question mark to some answer. So, if I can answer that question, if I can find even a clever way to answer that question faster, that is success. I have done a good job with my spike. STEPHANIE: I like that a lot. I think some people might struggle with spikes because they're so ambiguous. And if it's just, like, explore this potential feature, or, like, maybe not even that, but even saying, like, we want to build this admin role, to use Edward's example. And to constrain it to how should we do that, it already kind of guides the spike in a certain direction that may or may not be exactly what you're looking for. And so, there's some value in figuring out what questions to ask with the product team, even to get alignment on what the purpose of this task is. And, you know, this is true of regular feature work, too. When those decisions have kind of already been made about what we're working on without a lot of input from developers who will be working on it, it can be really hard to, like, go back and be like, "Oh, actually, that's not really possible." But if the questions are like, "Is this possible?" or like, what it costs to do this, I think it prevents some of that friction and misalignment that might be had when the outcome of a spike turns out to be maybe not what someone wants to hear. JOËL: And I think the questions you ask don't necessarily have to be yes or no questions. They could be some sort of list, right? It could be, look, we're looking at two different implementations or two general approaches, families of solutions for our super admin role. What are the trade-offs of each? And so, a spike might be exploring. Can we come up with a list of pros and cons for each approach? And maybe some of them we just know from experience at developing, but maybe some of them might involve actually doing a little bit of work to play out the pros and cons. Maybe that's in our app. Maybe that's even spinning up a little app on the side, right? If we're comparing maybe two gems or something like that to see how we feel about throwing a few different scenarios and exploring edge cases. So, the questions don't need to be straight-up yes or no. So, you mentioned earlier the idea that sometimes one developer might do the spike, and then another one might do the actual work, maybe inspired by the answers that were on that spike. And I think that can lead to some really interesting dynamics, especially if the developer who did the first spike has done kind of, like, what Edward describes, what feels like 90% of the feature. It may be not so great code quality. And then this is a branch on GitHub, and they're like, "Okay, do the rest. Make it good. I've already explored the possibilities here," and then you're the developer who has to pick that up. Have you ever experienced that? And if so, how do you feel picking up a ticket like that? STEPHANIE: Yeah, I have experienced it, and I think there is always something lost when that happens when you are not the person who did the research. And then having to just go from whatever was left in the notes or from the code and, you know, I don't know how feasible it is for whoever spiked to always be doing the implementing, but I certainly end up having a lot of questions, I think. Like, you can't document or even code out, like, every single thing you learned in that process, right? There's always from big to small decisions or alternatives considered that won't make it into however that communication or expression or knowledge transfer happens. And I think the two choices that I have as a developer picking that up is either to just trust [laughs] that the work the other person did is taking me down a good path or to spend more time rebuilding some of that context and making some of my own evaluations along the way and deciding for myself whether I'm like, oh yeah, this is a good idea, or maybe, like, I might change something here. So, I think that there is some time lost, too. And I think that's a really good thing to point out when someone might think like, oh, this is mostly done. That's kind of my first reaction in terms of the context loss in an exchange like that. JOËL: Do you feel like this is a situation where you would want to have the same developer do both the spike and the final implementation? Or is this maybe a situation where spikes aren't being done correctly, and maybe a branch with some code that's kind of half-written is maybe the wrong artifact to hand off from one developer to the other? STEPHANIE: Oh, that's really interesting about if that's the wrong artifact to hand off because it could be misleading. Maybe it's not always, and maybe there's some really great code that comes out of it if someone builds on top of a work-in-progress branch or a spike branch. Honestly, I think, and I haven't even really gotten to experience this all too much because maybe there is some perception that it's backtracking or, you know, it's more work or more time, but it would be really cool for whoever had spiked it to then bring someone along to pair on it and start fresh, like we mentioned, where they're kind of coming to each decision to be made with an idea, but it's not necessarily set in stone, right? There could be that discussion. It could be, like, a generative experience to either refine that code that had initially been spiked out or discover new things along the way. It's not like the outcome has already been decided because of the spike. It is information, and that's that. JOËL: And we on this podcast are very pro-discovering new things along the way. I think sometimes as a developer, if I get sort of a, you know, maybe a 90% branch done that's get passed on to me from somebody else who did a spike, it feels a little bit like the finish the rest of the owl meme, except that now I'm not even, like, just trying to follow a tutorial. Just somebody did the first couple of circles and then is like, "Oh yeah, you finish the rest of the owl. I did the hard work. You just need to polish it up." On the one hand, it's like, dude, if you're, like, doing 90%, you may as well finish it. I don't want to just be polishing somebody else's work. And, you know, oftentimes, it might feel like it's done 90% of the time, but it's actually, like, there's a lot of edge cases and nuance that have not been handled. And, you know, a spike is meant to be throwaway work to start with. So, I felt like those sorts of handoffs often, I don't know, they don't sit with me well. STEPHANIE: Yeah. You could also come in and be like, this doesn't even look like an owl at all [laughs]. JOËL: I feel like maybe in my ideal world, a branch with partly written code is, I guess, an intermediate artifact that might be useful to show. But what I really want from a spike is answers to questions that will allow me, when I build the thing from scratch to make intelligent decisions. So, probably what I want out of a spike is something that's closer to documentation, a list of questions that we were asking, and then the answers we came to by doing the spike work. And that might be maybe a list of trade-offs, or maybe we didn't really know the correct endpoints from this undocumented API, and we tried some stuff, and we, like, figured out what endpoints we needed, or what the shape of the JSON payload needed to be, things like that. Maybe we tried a couple of different implementations, or we did some exploration around, like, what gem we'd like to use, and we have a recommendation for a gem. Those are all, I think, very concrete outcomes from a spike that I can then use when I'm building it from scratch. And I'm not just, like, branching off your branch or having it open in another browser and copy-pasting snippets while trying to, like, add some testing and maybe modularizing it a little bit. I think that leads to probably a better outcome for the person who's doing the spike because they have a tighter scope and also a better outcome for me, who's then trying to build that feature correctly from the ground up. I think that would be my sort of ideal workflow. STEPHANIE: While you were saying that, I thought about how a lot of those points sounded like requirements for a feature. And that, I think, is also a good outcome when a spike then leads to more concrete requirements because those are all decisions that were thought through, right? And even better is if that also documents things that were tried and the trade-offs that came with them or, like, the reasons why they were less viable or not ideal for that added context because that is also work that happened [laughs] and should be captured so someone can know that that might not be time they need to spend on that. I am really interested in one piece that we haven't quite touched on is the complexity of the app and what it means for spiking to be a challenge because of the complexity of the app. JOËL: Yeah. And I think sort of inherent in there is that maybe the idea that if you have a really complex app, it sort of forces you to go to the 90% of the work done in order to successfully answer the questions you wanted to answer with your spike in a way that maybe a better-structured app would not. Do you think that's true? STEPHANIE: Well, I actually think that if the app is complex, you're actually seeing that affect all parts of feature development, not just spiking, where everything takes longer [laughs] because you maybe feel less confident. You're nervous about breaking something. Edward called the real work ensuring that it interacts with the entire system correctly, and that's true of, I think, just software development in general. And so, I wonder if, you know, spiking happens to be one way that it manifests, but if there are signals that it's affecting, you know, all parts of your workflow. JOËL: There definitely is a cost, right? Complex software imposes costs everywhere. In some way, I think maybe spiking is attempting to get around some of those, in that there are some decisions that we can just say, you know what? We'll build the feature, and we'll just kind of figure it out as we go along, and we'll, like, build the thing. Spiking attempts to say, look, let's not build the whole thing. Let's fake out a bunch of parts because, really, we have a big question that we want to answer about a thing that is three steps down, you know. And maybe the question is, look, we're trying to build the super admin role, and we know it's got all these, like, edge cases we need to deal with. Maybe we need a list of the edge cases, and maybe that's how we, like, try to drive them out. But maybe this is a, hey, do we want to go with more of a, like, a role hierarchy inheritance-based approach, or do we want to go with some sort of escalating defaults? Or whatever the couple of different strategies you might want to do. And the spike might be trying to answer the question, how can we, as cheaply as possible while doing the minimum amount of work, sort of explore which of these implementations works best? And in a complex system, is it possible to get to the answer to those questions without building out 90% of the feature itself? I think, going to what you said, you might have to do more work if it's a complex system. But I would also encourage everyone to go absolute minimalist, like, keep your goal in mind: what is the question you're trying to answer? And then ruthlessly cut everything you need to get to your point where you can answer that question. Do you need to hard code? Do you need to metaprogram? Do you need to do just, like, the worst, dirtiest code that you've ever written? That's okay because, like, the implementation does not matter. The fact that you're not exercising the full system does not matter, as long as the part that you're trying to exercise and answer your questions does get used. STEPHANIE: Yeah, I like that a lot. And I wonder if the impulse to want to spike something is coming out of nervousness about how complicated the ask is. And it's like, well, I don't want to tell you that it's going to take a long time because this app is extremely complex, and everything takes a long time. You know, it's like not wanting to face that hard question of either we need to just set our expectations that things take longer, or we need to make some kind of change to make that easier to work with. And that is a lot of thought and effort. And so, it's kind of an answer to be like, well, like, let me spike this out and then see [laughs]. And so it may be a way to appease someone making a request for a feature. I don't know; I'm perhaps projecting a little bit here [chuckles]. But it could also be an important question to ask yourself if you find your team, like, needing to lean on spikes a lot because you just don't know. JOËL: That's really interesting because I think that maybe connects to a recent episode we did on breaking features down into smaller chunks. Spikes can often manifest, or the need for a spike can often manifest when you've got a larger, less well-defined feature that you want to do. So, sometimes, breaking things into smaller pieces will help you have something that's a little bit more well-defined that you feel confident jumping into without doing a spike. Or maybe the act of trying to split this sort of large, undefined task into smaller pieces will reveal questions that need to be answered and say, look, I don't know where the seam should be, where to split this task because I don't know the answer to this one question. If I could know the answer to this one question, I would know where to split this feature. That's your spike right there. Do the minimum amount of code to answer that one question, and then you can split your feature and confidently work on the two smaller pieces. And I think that's a win for everyone. STEPHANIE: Yeah. And you can listen back to our vertical slice episode [laughs] for some inspiration on that. JOËL: On that note, shall we wrap up? STEPHANIE: Let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeeee!!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at: tbot.io/referral. Or you can email us at referrals@thoughtbot.com with any questions.
Stephanie shares her task of retiring a small, internally-used link-shortening app. She describes the process as both celebratory and a bit mournful. Meanwhile, Joël discusses his deep dive into ActiveRecord, particularly in the context of debugging. He explores the complexities of ActiveRecord querying schemas and the additional latency this introduces. Together, the hosts discuss the nuances of package management systems and their implications for developers. They touch upon the differences between system packages and language packages, sharing personal experiences with tools like Homebrew, RubyGems, and Docker. Transcript: JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. STEPHANIE: And I'm Stephanie Minn. And together, we're here to share a bit of what we've learned along the way. JOËL: So, Stephanie, what's new in your world? STEPHANIE: So, this week, I got to have some fun working on some internal thoughtbot work. And what I focused on was retiring one of our just, like, small internal self-hosted on Heroku apps in favor of going with a third-party service for this functionality. We basically had a tiny, little app that we used as a link-shortening service. So, if you've ever seen a tbot.io short link out in the world, we were using our just, like, an in-house app to do that, you know, but for various reasons, we wanted to...just it wasn't worth maintaining anymore. So, we wanted to just use a purchased service. But today, I got to just, like, do the little bit of, like, tidying up, you know, in preparation to archive a repo and kind of delete the app from Heroku, and I hadn't done that before. So, it felt a little bit celebratory and a little bit mournful even [laughs] to, you know, retire something like that. And I was pairing with another thoughtbot developer, and we used a pairing app called Tuple. And you can just send, like, fun reactions to each other. Like, you could send, like, a fire emoji [laughs] or something if that's what you're feeling. And so, I sent some, like, confetti when we clicked the, "I understand what deleting this app means on GitHub." But I joked that "Actually, I feel like what I really needed was a, like, a salute kind of like thank you for your service [laughs] type of reaction." JOËL: I love those moments when you're kind of you're hitting those kind of milestone-y moments, and then you get to send a reaction. I should do that more often in Tuple. Those are fun. STEPHANIE: They are fun. There's also a, like, table flip reaction, too, is one that I really enjoy [laughs], you know, you just have to manifest that energy somehow. And then, after we kind of sent out an email to the company saying like, "Oh yeah, we're not using our app anymore for link shortening," someone had a great suggestion to make our archived repo public instead of private. I kind of liked it as a way of, like, memorializing this application and let community members see, you know, real code in a real...the application that we used here at thoughtbot. So, hopefully, if not me, then someone else will be able to do that and maybe publish a little blog post about that. JOËL: That's exciting. So, it's not currently public, the repo, but it might be at some point in the future. STEPHANIE: Yeah, that's right. JOËL: We'll definitely have to mention it on a future episode if that happens so that people following along with the story can go check out the code. STEPHANIE: So, Joël, what's new in your world? JOËL: I've been doing a deep dive into how ActiveRecord works. Particularly, I am debugging some pretty significant slowdowns in querying ActiveRecord models that are backed not by a regular Postgres database but instead a Snowflake data warehouse via an ODBC connection. So, there's a bunch of moving pieces going on here, and it would just take forever to make any queries. And sure, the actual reported query time is longer than for a local Postgres database, but then there's this sort of mystery extra waiting time, and I couldn't figure out why is it taking so much longer than the actual sort of recorded query time. And I started digging into all of this, and it turns out that in addition to executing queries to pull actual data in, ActiveRecord needs to, at various points, query the schema of your data store to pull things like names of tables and what are the indexes and primary keys and things like that. STEPHANIE: Wow. That sounds really cool and something that I have never needed to do before. I'm curious if you noticed...you said that it takes, I guess, longer to query Snowflake than it would a more common Postgres database. Were you noticing this performance slowness locally or on production? JOËL: Both places. So, the nice thing is I can reproduce it locally, and locally, I mean running the Rails app locally. I'm still talking to a remote Snowflake data warehouse, which is fine. I can reproduce that slowness locally, which has made it much easier to experiment and try things. And so, from there, it's really just been a bit of a detective case trying to, I guess, narrow the possibility space and try to understand what are the parts that trigger slowness. So, I'm printing timestamps in different places. I've got different things that get measured. I've not done, like, a profiling tool to generate a flame graph or anything like that. That might have been something cool to try. I just did old-school print statements in a couple of places where I, like, time before, time after, print the delta, and that's gotten me pretty far. STEPHANIE: That's pretty cool. What do you think will be an outcome of this? Because I remember you saying you're digging a little bit into ActiveRecord internals. So, based on, like, what you're exploring, what do you think you could do as a developer to increase some of the performance there? JOËL: I think probably what this ends up being is finding that the Snowflake adapter that I'm using for ActiveRecord maybe has some sort of small bug in it or some implementation that's a little bit too naive that needs to be fine-tuned. And so, probably what ends up happening here is that this finishes as, like, an open-source pull request to the Snowflake Adapter gem. STEPHANIE: Yeah, that's where I thought maybe that might go. And that's pretty cool, too, and to, you know, just be investigating something on your app and being able to make a contribution that it benefits the community. JOËL: And that's what's so great about open source because not only am I able to get the source to go source diving through all of this, because I absolutely need to do that, but also, then if I make a fix, I can push that fix back out to the community, and everybody gets to benefit. STEPHANIE: Cool. Well, that's another thing that I look forward to hearing more on the development of [laughs] later if it pans out that way. JOËL: One thing that has been interesting with this Snowflake work is that there are a lot of moving parts and multiple different packages that I need to install to get this all to work. So, I mentioned that I might be doing a pull request against the Snowflake Adapter for ActiveRecord, but all of this talks through a sort of lower-level technology protocol called ODBC, which is a sort of generic protocol for speaking to data stores, and that actually has two different pieces. I had to install two different packages. There is a sort of low-level executable that I had to install on my local dev machine and that I have to install on our servers. And on my Mac, I'm installing that via Homebrew, which is a system package. And then to get Ruby bindings for that, there is a Ruby gem that I install that allows Ruby code to talk to ODBC, and that's installed via RubyGems or Bundler. And that got me thinking about sort of these two separate ecosystems that I tend to work with every day. We've got sort of the system packages and the, I don't know what you want to call them, language packages maybe, things like RubyGems, but that could also be NPM or whatever your language of choice is, and realizing that we kind of have things split into two different zones, and sometimes we need both and wondering a little bit about why is that difference necessary. STEPHANIE: Yeah, I don't have an answer to that [laughs] question right now, but I can say that that was an area that really tripped me up, I think, when I was first a fledgling developer. And I was really confused about where all of these dependencies were coming from and going through, you know, setting up my first project and being, like, asked to install Postgres on my machine but then also Bundler, which then also installs more dependencies [laughs]. The lines between those ecosystems were not super clear to me. And, you know, even now, like, I find myself really just kind of, like, learning what I need to know to get by [laughs] with my day-to-day work. But I do like what you said about these are kind of the two main layers that you're working with in terms of package management. And it's really helpful to have that knowledge so you can troubleshoot when there is an issue at one or the other. JOËL: And you mentioned Postgres. That's another one that's interesting because there are components in both of those ecosystems. Postgres itself is typically installed via a system package manager, so something like Homebrew on a Mac or apt-get on a Linux machine. But then, if you're interacting with Postgres in a Ruby app, you're probably also installing the pg gem, which are Ruby's bindings for Postgres to allow Ruby to talk to Postgres, and that lives in the package ecosystem on RubyGems. STEPHANIE: Yeah, I've certainly been in the position of, you know, again, as consultants, we oftentimes are also setting up new laptops entirely [laughs] like client laptops and such and bundling and the pg gem is installed. And then at least I have, you know, I have to give thanks to the very clear error message that [laughs] tells me that I don't have Postgres installed on my machine. Because when I mentioned, you know, troubleshooting earlier, I've certainly been in positions where it was really unclear what was going on in terms of the interaction between what I guess we're calling the Ruby package ecosystem and our system level one. JOËL: Especially for things like the pg gem, which need to compile against some existing libraries, those always get interesting where sometimes they'll fail to compile because there's a path to some C compiler that's not set correctly or something like that. For me, typically, that means I need to update the macOS command line tools or the Xcode command line tools; I forget what the name of that package is. And, usually, that does the trick. That might happen if I've upgraded my OS version recently and haven't downloaded the latest version of the command line tools. STEPHANIE: Yeah. Speaking of OS versions, I have a bit of a story to share about using...I've never said this name out loud, but I am pretty sure that it would just be pronounced as wkhtmltopdf [laughs]. For some reason, whenever I see words like that in my brain, I want to, like, make it into a pronounceable thing [laughs]. JOËL: Right, just insert some vowels in there. STEPHANIE: Yeah, wkhtmltopdf [laughs]. Anyway, that was being used in an app to generate PDF invoices or something. It's a pretty old tool. It's a CLI tool, and it's, as far as I can tell, it's been around for a long time but was recently no longer maintained. And so, as I was working on this app, I was running into a bug where that library was causing some issues with the PDF that was generated. So, I had to go down this route of actually finding a Ruby gem that would figure out which package binary to use, you know, based off of my system. And that worked great locally, and I was like, okay, cool, I fixed the issue. And then, once I pushed my change, it turns out that it did not work on CI because CI was running on Ubuntu. And I guess the binary didn't work with the latest version of Ubuntu that was running on CI, so there was just so many incompatibilities there. And I was wanting to fix this bug. But the next step I took was looking into community-provided packages because there just simply weren't any, like, up-to-date binaries that would likely work with these new operating systems. And I kind of stopped at that point because I just wasn't really sure, like, how trustworthy were these community packages. That was an ecosystem I didn't know enough about. In particular, I was having to install some using apt from, you know, just, like, some Linux community. But yeah, I think I normally have a little bit more experience and confidence in terms of the Ruby package ecosystem and can tell, like, what gems are popular, which ones are trustworthy. There are different heuristics I have for evaluating what dependency to pull in. But here I ended up just kind of bailing out of that endeavor because I just didn't have enough time to go down that rabbit hole. JOËL: It is interesting that learning how to evaluate packages is a skill you have to learn that varies from package community to package community. I know that when I used to be very involved with Elm, we would often have people who would come to the Elm community from the JavaScript community who were used to evaluating NPM packages. And one of the metrics that was very popular in the JavaScript community is just stars on GitHub. That's a really important metric. And that wasn't really much of a thing in the Elm community. And so, people would come and be like, "Wait, how do I know which package is good? I don't see any stars on GitHub." And then, it turns out that there are other metrics that people would use. And similarly, you know, in Ruby, there are different ways that you might use to evaluate Ruby gems that may or may not involve stars on GitHub. It might be something entirely different. STEPHANIE: Yeah. Speaking of that, I wanted to plug a website that I have used before called the Ruby Toolbox, and that gives some suggestions for open-source Ruby libraries of various categories. So, if you're looking for, like, a JSON parser, it has some of the more popular ones. If you're looking for, you know, it stores them by category, and I think it is also based on things like stars and forks like that, so that's a good one to know. JOËL: You could probably also look at something like download numbers to see what's popular, although sometimes it's sort of, like, an emergent gem that's more popular. Some of that almost you just need to be a little bit in the community, like, hearing, you know, maybe listening to podcasts like this one, subscribing to Ruby newsletters, going to conferences, things like that, and to realize, okay, maybe, you know, we had sort of an old staple for JSON parsing, but there's a new thing that's twice as fast. And this is sort of becoming the new standard, and the community is shifting towards that. You might not know that just by looking at raw stats. So, there's a human component to it as well. STEPHANIE: Yeah, absolutely. I think an extension of knowing how to evaluate different package systems is this question of like, how much does an average developer need to know about package management? [laughs] JOËL: Yeah, a little bit to a medium amount, and then if you're writing your own packages, you probably need to know a little bit more. But there are some things that are really maybe best left to the maintainers of package managers. Package managers are actually pretty complex pieces of software in terms of all of the dependency management and making sure that when you say, "Oh, I've got Rails, and this other gem, and this other gem, and it's going to find the exact versions of all those gems that play nicely together," that's non-trivial. As a sort of working developer, you don't need to know all of the algorithms or the graph theory or any of that that underlies a package manager to be able to be productive in your career. And even as a package developer, you probably don't need to really know a whole lot of that. STEPHANIE: Yeah, that makes sense. I actually had referred to our internal at thoughtbot here, our kind of, like, expectations for skill levels for developers. And I would say for an average developer, we kind of just expect a basic understanding of these more complex parts of our toolchain, I think, specifically, like, command line tools and package management. And I think I'd mentioned earlier that, for me, it is a very need-to-know basis. And so, yeah, when I was going down that little bit of exploration around why wkhtmltopdf [chuckles] wasn't working [chuckles], it was a bit of a twisty and turning journey where I, you know, wasn't really sure where to go. I was getting very obtuse error messages, and, you know, I had to dive deep into all these forums [laughs] for all the various platforms [laughs] about why libraries weren't working. And I think what I did come away with was that like, oh, like, even though I'm mostly working on my local machine for development, there was some amount of knowledge I needed to have about the systems that my CI and, you know, production servers are running on. The project I was working on happened to have, like, a Docker file for those environments, and, you know, kind of knowing how to configure them to install the packages I needed to install and just knowing a little bit about the different ways of doing that on systems outside of my usual daily workflows. JOËL: And I think that gets back to some of the interesting distinctions between what we might call language packages versus system packages is that language packages more or less work the same across all operating systems. They might have a build step that's slightly different or something like that, but system packages might be pretty different between different operating systems. So, development, for me, is a Mac, and I'm probably installing system packages via something like Homebrew. If I then want that Rails app to run on CI or some Linux server somewhere, I can't use Homebrew to install things there. It's going to be a slightly different package ecosystem. And so, now I need to find something that will install Postgres for Linux, something that will install, I guess, wkhtmltopdf [laughs] for Linux. And so, when I'm building that Docker file, that might be a little bit different for Mac versus for...or I guess when you run a Docker file, you're running a containerized system. So, the goal there is to make this system the same everywhere for everyone. But when you're setting that up, typically, it's more of a Linux-like system. And so running inside the Docker container versus outside on the native Mac might involve a totally different set of packages and a different package tool. As opposed to something like Bundler, you've got your gem file; you bundle install. It doesn't matter if you're on Linux or macOS. STEPHANIE: Yes, I think you're right. I think we kind of answered our own question at the top of the show [laughs] about differences and what do you need to know about them. And I also like how you pointed out, oh yeah, like, Docker is supposed to [laughs], you know, make sure that we're all developing in the same system, essentially. But, you know, sometimes you have different use cases for it. And, yeah, when you were talking about installing an application on your native Mac and using Homebrew, but even, you know, not everyone even uses Homebrew, right? You can install manually [laughs] through whatever official installer that application might provide. So, there's just so many different ways of doing something. And I had the thought that it's too bad that we both [chuckles] develop on Mac because it could be really interesting to get a Linux user's perspective in here. JOËL: You mentioned not installing via Homebrew. A kind of glaring example of that in my personal setup is that I use Postgres.app to manage Postgres on my machine rather than using Homebrew. I've just...over the years, the Homebrew version every time I upgrade my operating system or something, it's just such a pain to update, and I've lost too many hours to it, and Postgres.app just works, and so I've switched to that. Most other things, I'll use the Homebrew version, but Postgres it's now Postgres.app. It's not even a command line install, and it works fine for me. STEPHANIE: Nice. Yeah. That's interesting. That's a good tip. I'll have to look into that next time because I have also certainly had to just install so many [laughs] various versions of Postgres and figure out what's going on with them every time I upgrade my OS. I'm with you, though, in terms of the packages world I'm looking for, it works [laughs]. JOËL: So, you'd mentioned earlier that packages is sort of an area that's a bit of a need-to-know basis for you. Are there, like, particular moments in your career that you remember like, oh, that's the moment where I needed to, like, take some time and learn a little bit of the next level of packages? STEPHANIE: That's a great question. I think the very beginnings of understanding how package versions work when you have multiple projects on your machine; I just remember that being really confusing for me. When I started out, like, you know, as soon as I cloned my second repo [laughs], and was very confused about, like, I'm sure I went through the process of not installing gems using Bundler, and then just having so much chaos [laughs] wrecked in my development environment and, you know, having to ask someone, "I don't understand how this works. Like, why is it saying I have multiple versions of this library or whatever?" JOËL: Have you ever sudo gem installed a gem? STEPHANIE: Oh yeah, I definitely have. I can't [laughs], like, even give a good reason for why I have done it, but I probably was just, like, pulling my hair out, and that's what Stack Overflow told me to do. I don't know if I can recommend that, but it is [chuckles] one thing to do when you just are kind of totally stuck. JOËL: There was a time where I think that that was in the READMEs for most projects. STEPHANIE: Yeah, that's a really good point. JOËL: So, that's probably why a lot of people end up doing that, but then it tends to install it for your system Ruby rather than for...because if you're using something like Rbenv or RVM or ASDF to manage multiple Ruby versions, those end up being what's using or even Homebrew to manage your Ruby. It wouldn't be installing it for those versions of Ruby. It would be installing it for the one that shipped with your Mac. I actually...you know what? I don't even know if Mac still ships with Ruby. It used to. It used to ship with a really old version of Ruby, and so the advice was like, "Hey, every repo tells you to install it with sudo; don't do that. It will mess you up." STEPHANIE: Huh. I think Mac still does ship with Ruby, but don't quote me on that [laughter]. And I think that's really funny that, like, yeah, people were just writing those instructions in READMEs. And I'm glad that we've collectively [laughs] figured out that difference and want to, hopefully, not let other developers fall into that trap [laughs]. Do you have a particular memory or experience when you had to kind of level up your knowledge about the package ecosystem? JOËL: I think one sort of moment where I really had to level up is when I started really needing to understand how install paths worked, especially when you have, let's say, multiple versions of a gem installed because you have different projects. And you want to know, like, how does it know which one it's using? And then you see, oh, there are different paths that point to different directories with the installs. Or when you might have an executable you've installed via Homebrew, and it's like, oh yeah, so I've got this, like, command that I run on my shell, but actually that points to a very particular path, you know, in my Homebrew directory. But maybe it could also point to some, like, pre-installed system binaries or some other custom things I've done. So, there was a time where I had to really learn about how the path shell variable worked on a machine in order to really understand how the packages I installed were sometimes showing up when I invoked a binary and sometimes not. STEPHANIE: Yeah, that is another really great example that I have memories of [laughs] being really frustrated by, especially if...because, you know, we had talked earlier about all the different ways that you can install applications on your system, and you don't always know where they end up [laughs]. JOËL: And this particular memory is tied to debugging Postgres because, you know, you're installing Postgres, and some paths aren't working. Or maybe you try to update Postgres and now it's like, oh, but, like, I'm still loading the wrong one. And why does PSQL not do the thing that I think it does? And so, that forced me to learn a little bit about, like, under the hood, what happens when I type brew install PostgreSQL? And how does that mesh with the way my shell interprets commands and things like that? So, it was maybe a little bit of a painful experience but eye-opening and definitely then led to me, I think, being able to debug my setup much more effectively in the future. STEPHANIE: Yeah. I like that you also pointed out how it was interacting with your shell because that's, like, another can of worms, right? [laughs] In terms of just the complexity of how these things are talking to each other. JOËL: And for those of our listeners who are not familiar with this, there is a shell command that you can use called which, W-H-I-C-H. And you can prefix that in front of another command, and it will tell you the path that it's using for that binary. So, in my case, if I'm looking like, why is this PSQL behaving weirdly or seems to be using the old version, I can type 'which space psql', and it'll say, "Oh, it's going to this path." And I can look at it and be like, oh, it's using my system install of Postgres. It's not using the Homebrew one. Or, oh, maybe it's using the Homebrew install, not my Postgres.app version. I need to, like, tinker with the paths a little bit. So, that has definitely helped me debug my package system more than once. STEPHANIE: Yeah, that's a really good tip. I can recall just totally uninstalling everything [laughs] and reinstalling and fingers crossed it would figure out a route to the right thing [laughs]. JOËL: You know what? That works. It's not the, like, most precise solution but resetting your environment when all else fails it's not a bad solution. So, we've been talking a lot about what it's like to interact with a package ecosystem as developers, as users of packages, but what if you're a package developer? Sometimes, there's a very clear-cut place where to publish, and sometimes it's a little bit grayer. So, I could see, you know, I'm developing a database, and I want that to be on operating systems, probably should be a system-level package rather than a Ruby gem. But what if I'm building some kind of command line tool, and I write it in Ruby because I like writing Ruby? Should I publish that as a gem, or should I publish that as some kind of system package that's installed via Homebrew? Any opinions or heuristics that you would use to choose where to publish on one side or the other? STEPHANIE: As not a package developer [laughs], I can only answer from that point of view. That is interesting because if you publish on a, you know, like, a system repository, then yeah, like, you might get a lot more people using your tool out there because you're not just targeting a specific language's community. But I don't know if I have always enjoyed downloading various things to my system's OS. I think that actually, like, is a bit complicated for me or, like, I try to avoid it if I can because if something can be categorized or, like, containerized in a way that, like, feels right for my mental model, you know, if it's written in Ruby or something really related to things I use Ruby in, it could be nice to have that installed in my, like, systems RubyGems. But I would be really interested to hear if other people have opinions about where they might want to publish a package and what kind of developers they're hoping to find to use their tool. JOËL: I like the heuristic that you mentioned here, the idea of who the audience is because, yeah, as a Ruby developer who already has a Ruby setup, it might be easier for me to install something via a gem. But if I'm not a Ruby developer who wants to use the packages maybe a little bit more generic, you know, let's say, I don't know, it's some sort of command line tool for interacting with GitHub or something like that. And, like, it happens to be written in Ruby, but you don't particularly care about that as a user of this. Maybe you don't have Ruby installed and now you've got to, like, juggle, like, oh, what is RubyGems, and Bundler, and all this stuff? And I've definitely felt that occasionally downloading packages sort of like, oh, this is a Python package. And you're going to need to, like, set up all this stuff. And it's maybe designed for a Python audience. And so, it's like, oh, you're going to set up a virtual environment and all these things. I'm like, I just want your command line tools. I don't want to install a whole language. And so, sometimes there can be some frustration there. STEPHANIE: Yeah, that is very true. Before you even said that, I was like, oh, I've definitely wanted to download a command line tool and be like, first install [laughs] Python. And I'm like, nope, I'm bailing out of this. JOËL: On the other hand, as a developer, it can be a lot harder to write something that's a bit more cross-platform and managing all that. And I've had to deal a little bit with this for thoughtbot's Parity tool, which is a command-line tool for working with Heroku. It allows you to basically run commands on either staging or production by giving you a staging command and a production command for common Heroku CLI tasks, which makes it really nice if you're working and you're having to do some local, some development, some staging, and some production things all from your command line. It initially started as a gem, and we thought, you know what? This is mostly command line, and it's not just Rubyists who use Heroku. Let's try to put this on Homebrew. But then it depends on Ruby because it's written in Ruby. And now we had to make sure that we marked Ruby as a dependency in Homebrew, which meant that Homebrew would then also pull in Ruby as a dependency. And that got a little bit messy. For a while, we even experimented with sort of briefly available technology called Traveling Ruby that allowed you to embed Ruby in your binary, and you could compile against that. That had some drawbacks. So, we ended up rolling that back as well. And eventually, just for maintenance ease, we went back to making this a Ruby gem and saying, "Look, you install it via RubyGems." It does mean that we're targeting more of the Ruby community. It's going to be a little bit harder for other people to install, but it is easier for us to maintain. STEPHANIE: That's really interesting. I didn't know that history about Parity. It's a tool that I have used recently and really enjoyed. But yeah, I think I remember someone having some issues between installing it as a gem and installing it via Homebrew and some conflicts there as well. So, I can also see how trying to decide or maybe going down one path and then realizing, oh, like, maybe we want to try something else is certainly not trivial. JOËL: I think, in me, I have a little bit of the idealist and the pragmatist that fight. The idealist says, "Hey, if it's not, like, aimed for Ruby developers as a, like, you can pull this into your codebase, if it's just command line tools and the fact that it's written in Ruby is an implementation detail, that should be a system package. Do not distribute binaries via RubyGems." That's the idealist in me. The pragmatist says, "Oh, that's a lot of work and not always worth it for both the maintainers and sometimes for the users, and so it's totally okay to ship binaries as RubyGems." STEPHANIE: I was totally thinking that I'm sure that you've been in that position of being a user and trying to download a system package and then seeing it start to download, like, another language. And you're like, wait, what? [laughter] That's not what I want. JOËL: So, you and I have shared some of our heuristics in the way we approach this problem. Now, I'm curious to hear from the audience. What are some heuristics that you use to decide whether your package is better shipped on RubyGems versus, let's say, Homebrew? Or maybe as a user, what do you prefer to consume? STEPHANIE: Yes. And speaking of getting listener feedback, we're also looking for some listener questions. We're hoping to do a bit of a grab-bag episode where we answer your questions. So, if you have anything that you're wanting to hear me and Joël's thoughts on, write us at hosts@bikeshed.fm. JOËL: On that note, shall we wrap up? STEPHANIE: Let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at: tbot.io/referral. Or you can email us at referrals@thoughtbot.com with any questions.
Joël shares a unique, time-specific bug he encountered, which causes a page to crash only in January. This bug has been fixed in previous years, only to reemerge due to subsequent changes. Stephanie talks about her efforts to bring more structure to her work-from-home environment. She describes how setting up a bird feeder near her desk and keeping chocolates at her desk serve as incentives to work more from her desk. Together, Stephanie and Joël take a deep dive into the challenges of breaking down software development tasks into smaller, more manageable chunks. They explore the concept of 'vertical slice' development, where features are implemented in thin, fully functional segments, contrasting it with the more traditional 'horizontal slice' approach. This discussion leads to insights on collaborative work, the importance of iterative development, and strategies for efficient and effective software engineering. thoughtbot Live Streams (https://www.youtube.com/@thoughtbot/streams?themeRefresh=1) Stephanie's Live Stream (https://www.youtube.com/watch?v=jWmCOMbOxTs) Joël's Talk on Time (https://www.youtube.com/watch?v=54Hs2E7zsQg) Finish the Owl Meme (https://knowyourmeme.com/photos/572078-how-to-draw-an-owl) Full Stack Slices (https://thoughtbot.com/blog/break-apart-your-features-into-full-stack-slices) Elephant Carpaccio (https://blog.crisp.se/2013/07/25/henrikkniberg/elephant-carpaccio-facilitation-guide) Outside-in Feature Development (https://thoughtbot.com/blog/testing-from-the-outsidein) Working Iteratively (https://thoughtbot.com/blog/working-iteratively) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world in the year 2024? JOËL: Yeah, it's 2024. New year, new me. Or, in this case, maybe new year, new bugs? I'm working on a project where I ran into a really interesting time-specific bug. This particular page on the site only crashes in the month of January. There's some date logic that has a weird boundary condition there, and if you load that page during the month of January, it will crash, but during the entire rest of the year, it's fine. STEPHANIE: That's a fun New Year's tradition for this project [laughs], fixing this bug [laughs] every year. JOËL: It's been interesting because I looked a little bit at the git history of this bug, and it looks like it's been fixed in past Januarys, but then the fix changes the behavior slightly, so people bring the behavior back correct during the rest of the year that also happens to reintroduce the bug in January, and now I'm back to fixing it in January. So, it is a little bit of a tradition. STEPHANIE: Yeah, that is really funny. I was also recently debugging something, and we were having some flakiness with a test that we wrote. And we were trying to figure out because we had some date/time logic as well. And we were like, is there anything strange about this current time period that we are in that would potentially, you know, lead to a flaky test? And we were looking at the clock and we're like, "I don't think it's like, you know, midnight UTC or anything [laughs] like that." But, I mean, I don't know. It's like, how could you possibly think of, like, all of the various weird edge cases, you know, related to that kind of thing? I don't think I would ever be like, huh, it's January, so, surely, that must [laughs] mean that that's this particular edge case I'm seeing. JOËL: It's interesting because I feel like there's a couple of types of time-specific bugs that we see pretty frequently. If you're near the daylight savings boundary, let's say a week before sometimes, or whatever you're...if you're doing, like, a week from now logic or something like that, typically, I'll see failures in the test suite or maybe actual crashes in the code a week before springing forward and a week before falling back. And then, like you said, sometimes you see failures at the end of the day, Eastern time for me, when you approach that midnight UTC time boundary. I think this is the first time I've seen a failure in January due to the month being, like, a month boundary...or it's a year boundary really is what's happening. STEPHANIE: Yeah. That just sounds like another [laughs] thing you have to look out for. I'm curious: are you going to fix this bug for real or leave it for [laughs] 2025? JOËL: I've got a fix that I think is for real and that, like, not only fixes the break in January but also during the rest of the year gives the desired behavior. I think part of what's really interesting about this bug is that there are some subtle behavioral changes between a few different use cases where this code is called, part of which depend on when in the year you're calling it and whether you want to see it for today's date versus you can also specify a date that you want to see this report. And so, it turns out that there are a lot more edge cases than might be initially obvious. So, this turned into effectively a product discussion, and realizing, wait a minute, the code isn't telling the full story. There's more at a product level we need to discuss. And actually, I think I learned a lot about the product there. So, while it was maybe a surprising and kind of humorous bug to come across, I think it was actually a really good experience. STEPHANIE: Nice. That's awesome. That's a pretty good way to start the year, I would say. JOËL: I'd say so. How about you? What's new in your world? STEPHANIE: So, I don't know, I think towards the end of the year, last year, I was in a bit of a slump where I was in that work-from-couch phase of [laughs] the year, you know, like, things are slowing down and I, you know, winter was starting here. I wanted to be cozy, so I'd, you know, set up on the couch with a blanket. And I realized that I really wasn't sitting at my desk at all, and I kind of wanted to bring a little bit of that structure back into my workday, so I [chuckles] added some incentives for me to sit at my desk, which include I recently got a bird feeder that attaches to the window in my office. So, when I sit at my desk, I can hopefully see some birds hanging out. They are very flighty, so I've only seen birds when I'm, like, in the other room. And I'm like, oh, like, there's a bird at the bird feeder. Like, let me get up close to, like, get to admire them. And then as soon as I, like [laughs], get up close to the window, they fly away. So, I'm hoping that if I sit at my desk more, I'll spontaneously see more birds, and maybe they'll get used to, like, a presence closer to the window. And then my second incentive is I now have little chocolates at my desk [laughs]. JOËL: Nice. STEPHANIE: I've just been enjoying, like, a little treat and trying to keep them as a...okay, I've worked at my desk for an hour, and now I get a little reward for that [laughs]. JOËL: I like that. Do you know what kind of species of birds have been coming to your feeder? STEPHANIE: Ooh, yes. So, we got this birdseed mix called Cardinal and Friends [laughs]. JOËL: I love that. STEPHANIE: So, I have seen, like, a really beautiful red male cardinal come by. We get some robins and some chickadees, I think. Part of what I'm excited for this winter is to learn more how to identify more bird species. And I usually like to be out in nature and stuff, and winter is a hard time to do that. So, this is kind of my way of [chuckles] bringing that more into my life during the season. So, this is our first episode after a little bit of a break for the holidays. There actually has been some content of ours that has been published out in the world on the internet [laughs] during this time. And just wanted to point out in the few weeks that there weren't any Bike Shed episodes, I ended up doing a thoughtbot Rails development livestream with thoughtbot CEO Chad Pytel, and that was my first-time live streaming code [laughs]. And it was a really cool experience. I'm glad I had this podcast experience. So, I'm like, okay, well I have, you know, that, like, ability to do stuff kind of off script and present in the moment. But yeah, that was a really cool thing that I got to do, and I feel a little bit more confident about doing those kinds in the future. JOËL: And for those who are not aware, Chad does–I think it's a weekly live stream on Fridays where he's doing various types of code. So, he's done some work on some internal projects. He did a series where he upgraded, I think, a Rails 2 app all the way to Rails 7, typically with a guest who's another teammate from thoughtbot working on a thing. So, for those of our listeners that might find interesting, we'll put a link in the show notes where you can go see that. I think it's on YouTube and on Twitch. STEPHANIE: Yes. JOËL: What did you pair on? What kind of project were you doing for the livestream? STEPHANIE: So, we were working on thoughtbot's internal application called Hub, which is where we have, like, our internal messaging features. It's where we do a lot of our business operations-y things [laughs]. So, all of the, like, agency work that we do, we use our in-house software for that, and so Chad and I were working on a feature to introduce something that would help out with how we staff team members on projects. In other content news [laughs], Joël, I think you have something to share as well. JOËL: Yeah. So, we've mentioned on past episodes that I gave a talk at RubyConf this past November all about what the concept of time actually means within a program and the different ways of representing it, and the fact that time isn't really a single thing but actually kind of multiple related quantities. And over the holiday break, the talks from that conference got published. I'm pretty excited that that is now out there. We'd mentioned that as a highlight in the previous episode, highlighting accomplishments for the year, but it just wasn't quite out yet. We couldn't link it there. So, I'll leave a link in the show notes for this episode for anyone who's interested in seeing that. STEPHANIE: Sounds like that talk is also timely for a debug you -- JOËL: Ha ha ha! STEPHANIE: Were also mentioning earlier in the episode. So, a few episodes ago, I believe we mentioned that we had recently had, like, our company internal hackathon type thing where we have two days to get together and work with team members who we might not normally work with and get some cool projects started or do some team bonding, that kind of thing. And since I'm still, you know, unbooked on client work, I've been doing a lot of internal thoughtbot stuff, like continuing to work on the Hub app I mentioned just a bit ago. And from the hackathon, there was some work that was unfinished by, like, a project team that I decided to pick up this week as part of my internal work. And as I was kind of trying to gauge how much progress was made and, like, what was left to accomplish to get it over the finish line so it could be shipped, I noticed that because there were a couple of different people working on it, they had broken up this feature which was basically introducing, like, a new report for one of our teams to get some data on how certain projects are going. And there was, like, a UI portion and then some back-end portion, and then part of the back-end portion also involved a bit of a complex query that was pulled out as a separate ticket on its own. And so, all of those things were slightly, you know, were mostly done but just needed those, like, finishing touches, and then it also needed to come together. And I ended up pairing on this with another thoughtboter, and we spent the same amount of time that the hackathon was, so two days. We spent those two days on that, like, aspect of putting it all together. And I think I was a bit surprised by how much work that was, you know, we had kind of assumed that like, oh, like, all these pieces are mostly finished, but then the bulk of what we spended our time doing was integrating the components together. JOËL: Does this feel like a bit of a finish the rest of the OWL meme? STEPHANIE: What is that meme? I'm not familiar with it, but now I really want to know [laughs]. JOËL: It's a meme kind of making fun of some of these drawing tutorials where they're like, oh; first you draw, like, three circles. STEPHANIE: [laughs] JOËL: And then just finish the rest of the owl. STEPHANIE: [laughs] JOËL: And I was thinking of this beautifully drawn picture. STEPHANIE: Oh, that's so funny. Okay, yeah, I can see it in my head [laughs] now. It's like how to go from three circles, you know, to a recognizable [laughs] owl animal. JOËL: So, especially, they're like, oh, you know, like, we put in all the core classes and everything. It's all just basically there. You just need to connect it all together, and it's basically done [laughs]. And then you spend a lot of time actually getting that what feels like maybe the last 20 or 10% but takes maybe 80% of the time. STEPHANIE: Yeah, that sounds about right. So, you know, kind of working on that got me thinking about the alternative, which is honestly something that I'm still working on getting better at doing in my day-to-day. But there is this idea of a vertical slice or a full-stack slice, and that, basically, involves splitting a large feature into those full-stack slices. So, you have, like, a fully implemented piece rather than breaking them apart by layers of the stack. So, you know, I just see pretty frequently that, like, maybe you'll have a back-end ticket to do the database migration, to create your models, just whatever, maybe your controllers, or maybe that is even, like, another piece and then, like, the UI component. And those are worked on separately, maybe even by different people. But this vertical slice theory talks about how what you really want is to have a very thin piece of the feature that still delivers value but fully works. JOËL: As opposed to what you might call a horizontal slice, which would be something like, oh, I've built three Rails models. They're there. They're in the code. They talk to tables in the database, but there's nothing else happening with them. So, you've done work, but it's also more or less dead code. STEPHANIE: Yeah, that's a good point. I have definitely seen a lot of unused code paths [laughs] when you kind of go about it that way and maybe, like, that UI ticket never gets completed. JOËL: What are some tips for trying to do some of these narrower slices? Like, I have a ticket, and I have some work I need to do. And I want to break it down because I know it's going to be too big, and maybe the, like, intuitive way to do it is to split it by layers of your stack where I might do all the models, commit, ship that, deploy, then do some controllers, then do some view, or something like that, and you're suggesting instead going full stack. How do you break down the ticket more when all the pieces are interrelated? STEPHANIE: Yeah, that's a great point. One easy way to visualize it, especially if you have designs or something for this feature, right? Oftentimes, you can start to parse out sections or components of the user interface to be shipped separately. Like, yes, you would want all of it to have that rich feature, but if it's a view of some cards or something, and then, yeah, there's, like, the you can filter by them. You can search by them. All of those bits can be broken up to be like, well, like, the very basic thing that a customer would want to see is just that list of cards, and you can start there. JOËL: So, aggressively breaking down the card at, like, almost a product level. Instead of breaking it down by technical pieces, say, like, can we get even smaller amounts of behavior while still delivering value? STEPHANIE: Yeah, yeah, exactly. I like that you said product level because I think another axis of that could also be complexity. So, oftentimes, you know, I'll get a feature, and we're like, oh, we want to support these X number of things that we've identified [laughs]. You know, if it's like an e-com app you're building, you know, you're like, "Do we have all these products that we want to make sure to support?" And, you know, one way to break that down into that vertical slice is to ask, like, what if we started with just supporting one before we add variants or something like that? Teasing out, like, what would end up being the added complexity as you're developing, once you have to start considering multiple parameters, I think that is a good way to be able to start working more iteratively. And so, you don't have to hold all of that complexity in your head. JOËL: It's almost a bit of like a YAGNI principle but applied to features rather than to code. STEPHANIE: Yeah. Yeah. I like that. At first, I hesitated a little bit because I've certainly been in the position where someone has said like, "Well, we do really need this [laughs]." JOËL: Uh-huh. And, sometimes, the answer is, yes, we do need that, but what if I gave you a smaller version of that today, and we can do the other thing tomorrow? STEPHANIE: Right. Yeah, it's not like you're rejecting the idea that it's necessary but the way that you get about to that end result, right? JOËL: So, you keep using the term vertical slice or full-stack slice. I think when I hear that term, I think of specifically an article written by former thoughtboter, German Velasco, on our blog. But I don't know if that's maybe a term that has broader use in the industry. Is that a term that you've heard elsewhere? STEPHANIE: That's a good question. I think I mostly hear, you know, some form of like, "Can we break this ticket down further?" and not necessarily, like, if you think about how, right? I'm, like, kind of doing a motion with my hand [chuckles] of, like, slicing from top to bottom as opposed to, you know, horizontal. Yeah, I think that it may not be as common as I wish it were. Even if there's still some amount of adapting or, like, persuading your team members to get on board with this idea, like, I would be interested in, like, introducing that concept or that vocabulary to get teams talking about, like, how do they break down tickets? You know, like, what are they considering? Like, what alternatives are there? Like, are horizontal slices working for them or not? JOËL: A term that I've heard floating around and I haven't really pinned down is Elephant Carpaccio. Have you heard that before? STEPHANIE: I have, only because I, like, discovered a, like, workshop facilitation guide to run an exercise that is basically, like, helping people learn how to identify, like, smaller and smaller full-stack slices. But with the Elephant Carpaccio analogy, it's kind of like you're imagining a feature as big as an elephant. And you can create, like, a really thin slice out of them, and you can have infinite number of slices, but they still end up creating this elephant. And I guess you still get the value of [chuckles] a little carpaccio, a delicious [laughs] appetizer of thinly sliced meat. JOËL: I love a colorful metaphor. So, I'm curious: in your own practice, do you have any sort of guidelines or even heuristics that you like to use to help work in a more, I guess, iterative fashion by working with these smaller slices? STEPHANIE: Yeah, one thought that I had about it is that it plays really well with Outside-In Test Driven Development. JOËL: Hmmm. STEPHANIE: Yeah. So, if, you know, you are starting with a feature test, you have to start somewhere and, you know, maybe starting with, like, the most valuable piece of the feature, right? And you are starting at that level of user interaction if you're using Capybara, for example. And then it kind of forces you to drop down deeper into those layers. But once you go through that whole process of outside-in and then you arrive back to the top, you've created your full-stack feature [laughs], and that is shippable or, like, committable and, you know, potentially even shippable in and of itself. And you already have full test coverage with it. And that was a cool way that I saw some of those two concepts work well together. JOËL: Yeah, there is something really fun about the sort of Red-Green-Refactor cycle that TDD forces on you and that you're typically writing the minimum code required to pass a test. And it really forces you out of that developer brain where you're just like, oh, I've got to cover my edge cases. I've got to engineer for some things. And then maybe you realize you've written code that wasn't necessary. And so, I've found that often when I do, like, actually TDD a feature, I end up with code that's a lot leaner than I would otherwise. STEPHANIE: Yes, lean like a thin slice of Elephant Carpaccio. [laughter] JOËL: One thing you did mention that I wanted to highlight was the fact that when you do this outside-in approach for your tiny slice, at the end, it is shippable. And I think that is a core sort of tenet of this idea is that even though you're breaking things down into smaller and smaller slices, every slice is shippable to production. Like, it doesn't break the build. It doesn't break the website. And it provides some kind of value to the user. STEPHANIE: Yeah, absolutely. I think one thing that I still kind of get hung up on sometimes, and I'm trying to, you know, revisit this assumption is that idea of, like, is this too small? Like, is this valuable enough? When I mentioned earlier that I was working on a report, I think there was a part of me that's like, could I just ship a report with two columns [laughs]? And the answer is yes, right? Like, I thought about it, and I was like, well, if that data is, like, not available anywhere else, then, yeah, like, that would be valuable to just get out there. But I think the idea that, like, you know, originally, the hope was to have all of these things, these pieces of information, you know, available through this report, I think that, like, held me back a little bit from wanting to break it down. And I held it a little bit too closely and to be like, well, I really want to, like, you know, deliver something impressive. When you click on it, it's like, wow, like, look at all this data [laughs]. So, I'm trying to push back a little bit on my own preconceived notions that, like, there is such a thing as, like, a too small of a demo. JOËL: I've often worked with this at a commit level, trying to see, like, how small can I get a commit, and what is too small? And now you get into sort of the fraught question of what is a, you know, atomic commit? And I think, for me, where I've sort of come down is that a commit must pass CI. Like, I don't want a commit that's going to go into the main branch. I'm totally pro-work-in-progress commits on a branch; that's fine. But if it's going to get shipped into the main branch, it needs to be green. And it also cannot introduce dead code. STEPHANIE: Ooh. JOËL: So, if you're getting to the point where you're breaking either of those, you've got some sort of, like, partial commit that's maybe too small that needs more to be functional. Or you maybe need to restructure to say, look, instead of adding just ten models, can I add one model but also a little bit of a controller and a view? And now I've got a vertical slice. STEPHANIE: Yeah, which might even be less code [laughs] in the end. JOËL: Yes, it might be less code. STEPHANIE: I really like that heuristic of not introducing dead code, that being a goal. I'm going to think about that a lot [laughs] and try to start introducing that into when I think something is ready. JOËL: Another thing that I'll often do, I guess, that's almost like it doesn't quite fit in the slice metaphor, but it's trying to separate out any kind of refactor work into its own commit that is, you know, still follows those rules: it does not introduce dead code; it does not break the build; it's independently shippable. But that might be something that I do that sets me up for success when I want to do that next slice. So, maybe I'm trying to add a new feature, but just the way we built some of the internal models, they don't have the interface that I need right now, and that's fine because I don't want to build these models in anticipation of the future. I can change them in the future if I need. But now the future has come, and I need a slightly different shape. So, I start by refactoring, commit, maybe even ship that deploy. Maybe I then do my small feature afterwards. Maybe I come back next week and do the small feature, but there are two independent things, two different commits, maybe two different deploys. I don't know that I would call that refactor a slice and that it maybe goes across the full stack; maybe it doesn't. It doesn't show to the user because a refactor, by definition, is just changing the implementation without changing behavior. But I do like to break that out and keep it separate. And I guess it helps keep my slices lean, but I'm not quite sure where refactors fit into this metaphor. STEPHANIE: Yeah, that's interesting because, in my head, as I was listening to you talk about that, I was visualizing the owl again, the [laughs] owl meme. And I'm imagining, like, the refactoring making the slice richer, right? It's like you're adding details, and you're...it's like when you end up with the full animal, or the owl, the elephant, whatever, it's not just, like, a shoddy-looking drawing [laughs]. Like, ideally, you know, it has those details. Maybe it has some feathers. It's shaded in, and it is very fleshed out. That's just my weird, little brain trying [laughs] to stretch this metaphor to make it work. Another thing that I want to kind of touch a little bit more about when we're talking about how a lot of the work I was spending recently was that glue work, you know, the putting the pieces together, I think there was some aspect of discovery involved that was missed the first time around when these tickets were broken up more horizontally. I think that one really important piece that I was doing was trying to reconcile the different mental models that each person had when they were working on their separate piece. And so, maybe there's, like, an API, and then the frontend is expecting some sort of data, and, you know, you communicate it in a way that's, like, kind of hand-off-esque. And then when you put it together, it turns out that, oh, the pieces don't quite fit together, and how do you actually decide, like, what that mental model should be? Naming, especially, too, I've, you know, seen so many times when the name...like, an attribute on the frontend is named a little bit different than whatever is on the backend, and it takes a lot of work to unify that, like, to make that decision about, should they be the same? Should they be different? A lot of thought goes into putting those pieces together. And I think the benefit of a full-stack slice is that that work doesn't get lost. Especially if you are doing stuff like estimating, you're kind of discovering that earlier on. And I think what I just talked about, honestly, is what prevents those features from getting shipped in the end if you were working in a more horizontal way. JOËL: Yeah. It's so easy to have, like, big chunks of work in progress forever and never actually shipping. And one of the benefits of these narrower slices is that you're shipping more frequently. And that's, you know, interesting from a coding perspective, but it's kind of an agile methodology thing as well, the, like, ship smaller chunks more frequently. Even though you're maybe taking a little bit more overhead because you're having to, like, take the time to break down tasks, it will make your project move faster as a whole. An aspect that's really interesting to me, though, is what you highlighted about collaboration and the fact that every teammate has a slightly different mental model. And I think if you take the full-stack slice and every member is able to use their mental model, and then close the loop and actually, like, do a complete thing and ship it, I think it allows every other member who's going to have a slightly different mental model of the problem to kind of, yes, and... the other person rather than all sort of independently doing their things and having to reconcile them at the end. STEPHANIE: Yeah, I agree. I think I find, you know, a lot of work broken out into backend and frontend frequently because team members might have different specialties or different preferences about where they would like to be working. But that could also be, like, a really awesome opportunity for pairing [laughs]. Like, if you have someone who's more comfortable in the backend or someone more comfortable in the frontend to work on that full-stack piece together, like, even outside of the in-the-weeds coding aspects of it, it's like you're, at the very least, making sure that those two folks have that same mental model. Or I like what you said about yes, and... because it gets further refined when you have people who are maybe more familiar with, like, something about the app, and they're like, "Oh, like, don't forget about we should consider this." I think that, like, diversity of experience, too, ends up being really valuable in getting that abstraction to be more accurate so that it best represents what you're trying to build. JOËL: Early on, when I was pretty new working at thoughtbot, somebody else at the company had given me the advice that if I wanted to be more effective and work faster on projects, I needed to start breaking my work down into smaller chunks, and this is, you know, fairly junior developer at the time. The advice sounds solid, and everything we've talked about today sounds really solid. Doing it in practice is hard, and it's taken me, you know, a decade, and I'm still working on getting better at it. And I wrote an article about working iteratively that covers a lot of different elements where I've kind of pulled on threads and found out ways where you can get better at this. But I do want to acknowledge that this is not something that's easy and that just like the code that we're working on iteratively, our technique for breaking things down is something that we improve on iteratively. And it's a journey we're all on together. STEPHANIE: I'm really glad that you brought up how hard it is because as I was thinking about this topic, I was considering barriers into working in that vertical slice way, and barriers that I personally experience, as well as just I have seen on other teams. I had alluded to some earlier about, like, the perception of if I ship this small thing, is it impressive enough, or is it valuable enough? And I think I realized that, like, I was getting caught up in, like, the perception part, right? And maybe it doesn't matter [chuckles], and I just need to kind of shift the way I'm thinking about it. And then, there are more real barriers or, like, concrete barriers that are tough. Long feedback loops is one that I've encountered on a team where it's just really hard to ship frequently because PR reviews aren't happening fast enough or your CI or deployment process is just so long that you're like, I want to stuff everything into [chuckles] this one PR so that at least I won't have to sit and wait [laughs]. And that can be really hard to work against, but it could also be a really interesting signal about whether your processes are working for you. It could be an opportunity to be like, "I would like to work this way, but here are the things that are preventing me from really embracing it. And is there any improvement I can make in those areas?" JOËL: Yeah. There's a bit of a, like, vicious cycle that happens there sometimes, especially around PR review, where when it takes a long time to get reviews, you tend to decide, well, I'm going to not make a bunch of PRs; I'm going to make one big one. But then big PRs are very, like, time intensive and require you to commit a lot of, like, focus and energy to them, which means that when you ask me for a review, I'm going to wait longer before I review it, which is going to incentivize you to build bigger PRs, which is going to incentivize me to wait longer, and now we just...it's a vicious cycle. So, I know I've definitely been on projects where a question the team has had is, "How can we improve our process? We want faster code review." And there's some aspect of that that's like, look, everybody just needs to be more disciplined or more alert and try to review things more frequently. But there's also an element of if you do make things smaller, you make it much easier for people to review your code in between other things. STEPHANIE: Yeah, I really liked you mentioning incentives because I think that could be a really good place to start if you or your team are interested in making a change like this, you know, making an effort to look at your team processes and being like, what is incentivized here, and what does our system encourage or discourage? And if you want to be making that shift, like, that could be a good place to start in identifying places for improvement. JOËL: And that happens on a broader system level as well. If you look at what does it take to go from a problem that is going to turn into a ticket to in-production in front of a client, how long is that loop? How complex are the steps to get there? The longer that loop is, the slower you're iterating. And the easier it is for things to just get hung up or for you to waste time, the harder it is for you to change course. And so, oftentimes, I've come on to projects with clients and sort of seen something like that, and sort of seen other pain points that the team has and sort of found that one of the root causes is saying, "Look, we need to tighten that feedback loop, and that's going to improve all these other things that are kind of constellation around it." STEPHANIE: Agreed. On that note, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at: tbot.io/referral. Or you can email us at referrals@thoughtbot.com with any questions.
Stephanie is hosting a holiday cookie swap. Joël talks about participating in thoughtbot's end-of-the-year hackathon, Ralphapalooza. We had a great year on the show! The hosts wrap up the year and discuss their favorite episodes, the articles, books, and blog posts they've read and loved, and other highlights of 2023 (projects, conferences, etc). Olive Oil Sugar Cookies With Pistachios & Lemon Glaze (https://food52.com/recipes/82228-olive-oil-sugar-cookies-recipe-with-pistachios-lemon) thoughtbot's Blog (https://thoughtbot.com/blog) Episode 398: Developing Heuristics For Writing Software (https://www.bikeshed.fm/398) Episode 374: Discrete Math (https://www.bikeshed.fm/374) Episode 405: Sandi Metz's Rules (https://www.bikeshed.fm/405) Episode 391: Learn with APPL (https://www.bikeshed.fm/391) Engineering Management for the Rest of Us (https://www.engmanagement.dev/) Confident Ruby (https://pragprog.com/titles/agcr/confident-ruby/) Working with Maybe from Elm Europe (https://www.youtube.com/watch?v=43eM4kNbb6c) Sustainable Rails Book (https://sustainable-rails.com/) Episode 368: Sustainable Web Development (https://www.bikeshed.fm/368) Domain Modeling Made Functional (https://pragprog.com/titles/swdddf/domain-modeling-made-functional/) Simplifying Tests by Extracting Side Effects (https://thoughtbot.com/blog/simplify-tests-by-extracting-side-effects) The Math Every Programmer Needs (https://www.youtube.com/watch?v=wzYYT40T8G8) Mermaid.js sequence diagrams (https://mermaid.js.org/syntax/sequenc) Sense of Belonging and Software Teams (https://www.drcathicks.com/post/sense-of-belonging-and-software-teams) Preemptive Pluralization is (Probably) Not Evil (https://www.swyx.io/preemptive-pluralization) Digging through the ashes (https://everythingchanges.us/blog/digging-through-the-ashes/) Transcript: JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. STEPHANIE: And I'm Stephanie Minn. And together, we're here to share a bit of what we've learned along the way. JOËL: So, Stephanie, what's new in your world? STEPHANIE: I am so excited to talk about this. I'm, like, literally smiling [chuckles] because I'm so pumped. Sometimes, you know, we get on to record, and I'm like, oh, I got to think of something that's new, like, my life is so boring. I have nothing to share. But today, I am excited to tell you about [chuckles] the holiday cookie swap that I'm hosting this Sunday [laughs] that I haven't been able to stop thinking about or just thinking about all the cookies that I'm going to get to eat. It's going to be my first time throwing this kind of shindig, and I'm so pleased with myself because it's such a great idea. You know, it's like, you get to share cookies, and you get to have all different types of cookies, and then people get to take them home. And I get to see all my friends. And I'm really [chuckles] looking forward to it. JOËL: I don't think I've ever been to a cookie swap event. How does that work? Everybody shows up with cookies, and then you leave with what you want? STEPHANIE: That's kind of the plan. I think it's not really a...there's no rules [laughs]. You can make it whatever you want it to be. But I'm asking everyone to bring, like, two dozen cookies. And, you know, I'm hoping for a lot of fun variety. Myself I'm planning on making these pistachio olive oil cookies with a lemon glaze and also, maybe, like, a chewy ginger cookie. I haven't decided if I'm going to go so extra to make two types, but we'll see. And yeah, we'll, you know, probably have some drinks and be playing Christmas music, and yeah, we'll just hang out. And I'm hoping that everyone can kind of, like, take home a little goodie bag of cookies as well because I don't think we'll be going through all of them. JOËL: Hearing you talk about this gave me an absolutely terrible idea. STEPHANIE: Terrible or terribly awesome? [laughs] JOËL: So, imagine you have the equivalent of, let's say, a LAN party. You all show up with your laptops. STEPHANIE: [laughs] JOËL: You're on a network, and then you swap browser cookies randomly. STEPHANIE: [laughs] Oh no. That would be really funny. That's a developer's take on a cookie party [laughs] if I've ever heard one. JOËL: Slightly terrifying. Now I'm just browsing, and all of a sudden, I guess I'm logged into your Facebook or something. Maybe you only swap the tracking cookies. So, I'm not actually logged into your Facebook, but I just get to see the different ad networks it would typically show you, and you would see my ads. That's maybe kind of fun or maybe terrifying, depending on what kind of ads you normally see. STEPHANIE: That's really funny. I'm thinking about how it would just be probably very misleading and confusing for those [laughs] analytics spenders, but that's totally fine, too. Might I suggest also having real cookies to munch on as well while you are enjoying [laughs] this browser cookie-swapping party? JOËL: I 100% agree. STEPHANIE: [laughs] JOËL: I'm curious: where do you stand on raisins in oatmeal cookies? STEPHANIE: Ooh. JOËL: This is a divisive question. STEPHANIE: They're fine. I'll let other people eat them. And occasionally, I will also eat an oatmeal cookie with raisins, but I much prefer if the raisins are chocolate chips [chuckles]. JOËL: That is the correct answer. STEPHANIE: [laughs] Thank you. You know, I understand that people like them. They're not for me [laughs]. JOËL: It's okay. Fans can send us hate mail about why we're wrong about oatmeal cookies. STEPHANIE: Yeah, honestly, that's something that I'm okay with being wrong about on the internet [laughs]. So, Joël, what's new in your world? JOËL: So, as of this recording, we've just recently done thoughtbot's end-of-the-year hackathon, what we call Ralphapalooza. And this is sort of a time where you kind of get to do pretty much any sort of company or programming-related activity that you want as long as...you have to pitch it and get at least two other colleagues to join you on the project, and then you've got two days to work on it. And then you can share back to the team what you've done. I was on a project where we were trying to write a lot of blog posts for the thoughtbot blog. And so, we're just kind of getting together and pitching ideas, reviewing each other's articles, writing things at a pretty intense rate for a couple of days, trying to flood the blog with articles for the next few weeks. So, if you're following the blog and as the time this episode gets released, you're like, "Wow, there's been a lot of articles from the thoughtbot blog recently," that's why. STEPHANIE: Yes, that's awesome. I love how much energy that the blog post-writing party garnered. Like, I was just kind of observing from afar, but it sounds like, you know, people who maybe had started posts, like, throughout the year had dedicated time and a good reason to revisit them, even if they had been, you know, kind of just, like, sitting in a draft for a while. And I think what also seemed really nice was people were just around to support, to review, and were able to make that a priority. And it was really cool to see all the blog posts that are queued up for December as a result. JOËL: People wrote some great stuff. So, I'm excited to see all of those come out. I think we've got pretty much a blog post every day coming out through almost the end of December. So, it's exciting to see that much content created. STEPHANIE: Yeah. If our listeners want more thoughtbot content, check out our blog. JOËL: So, as mentioned, we're recording this at the end of the year. And I thought it might be fun to do a bit of a retrospective on what this year has been like for you and I, Stephanie, both in terms of different work that we've done, the learnings we've had, but maybe also look back a little bit on 2023 for The Bike Shed and what that looked like. STEPHANIE: Yes. I really enjoyed thinking about my year and kind of just reveling and having been doing this podcast for over a year now. And yeah, I'm excited to look back a little bit on both things we have mentioned on the show before and things maybe we haven't. To start, I'm wondering if you want to talk a little bit about some of our favorite episodes. JOËL: Favorite episodes, yes. So, I've got a couple that are among my favorites. We did a lot of good episodes this year. I really liked them. But I really appreciated the episode we did on heuristics, that's Episode 398, where we got to talk a little bit about what goes into a good heuristic, how we tend to come up with them. A lot of those, like, guidelines and best practices that you hear people talk about in the software world and how to make your own but then also how to deal with the ones you hear from others in the software community. So, I think that was an episode that the idea, on the surface, seemed really basic, and then we went pretty deep with it. And that was really fun. I think a second one that I really enjoyed was also the one that I did with Sara Jackson as a guest, talking about discrete math and its relevance to the day-to-day work that we do. That's Episode 374. We just had a lot of fun with that. I think that's a topic that more developers, more web developers, would benefit from just getting a little bit more discrete math in their lives. And also, there's a clip in there where Sara reinterprets a classic marketing jingle with some discrete math terms in there instead. It was a lot of fun. So, we'd recommend people checking that one out. STEPHANIE: Nice. Yes. I also loved those episodes. The heuristics one was really great. I'm glad you mentioned it because one of my favorite episodes is kind of along a similar vein. It's one of the more recent ones that we did. It's Episode 405, where we did a bit of a retro on Sandi Metz' Rules For Developers. And those essentially are heuristics, right? And we got to kind of be like, hey, these are someone else's heuristics. How do we feel about them? Have we embodied them ourselves? Do we follow them? What parts do we take or leave? And I just remember having a really enjoyable conversation with you about that. You and I have kind of treated this podcast a little bit like our own two-person book club [laughs]. So, it felt a little bit like that, right? Where we were kind of responding to, you know, something that we both have read up on, or tried, or whatever. So, that was a good one. Another one of my favorite episodes was Episode 391: Learn with APPL [laughs], in which we basically developed our own learning framework, or actually, credit goes to former Bike Shed host, Steph Viccari, who came up with this fun, little acronym to talk about different things that we all kind of need in our work lives to be fulfilled. Our APPL stands for Adventure, Passion, Profit, and Low risk. And that one was really fun just because it was, like, the opposite of what I just described where we're not discussing someone else's work but discovered our own thing out of, you know, these conversations that we have on the show, conversations we have with our co-workers. And yeah, I'm trying to make it a thing, so I'm plugging it again [laughs]. JOËL: I did really like that episode. One, I think, you know, this APPL framework is a little bit playful, which makes it fun. But also, I think digging into it really gives some insight on the different aspects that are relevant when planning out further growth or where you want to invest your sort of professional development time. And so, breaking down those four elements led to some really insightful conversation around where do I want to invest time learning in the next year? STEPHANIE: Yeah, absolutely. JOËL: By the way, we're mentioning a bunch of our favorite things, some past episodes, and we'll be talking about a lot of other types of resources. We will be linking all of these in the show notes. So, for any of our listeners who are like, "Oh, I wonder what is that thing they mentioned," there's going to be a giant list that you can check out. STEPHANIE: Yeah. I love whenever we are able to put out an episode with a long list of things [laughs]. JOËL: It's one of the fun things that we get to do is like, oh yeah, we referenced all these things. And there is this sort of, like, further reading, more threads to pull on for people who might be interested. So, you'd mentioned, Stephanie, that, you know, sometimes we kind of treat this as our own little mini, like, two-person book club. I know that you're a voracious reader, and you've mentioned so many books over the course of the year. Do you have maybe one or two books that have been kind of your favorites or that have stood out to you over 2023? STEPHANIE: I do. I went back through my reading list in preparation for this episode and wanted to call out the couple of books that I finished. And I think I have, you know, I mentioned I was reading them along the way. But now I get to kind of see how having read them influenced my work life this past year, which is pretty cool. So, one of them is Engineering Management for the Rest of Us by Sarah Drasner. And that's actually one that really stuck with me, even though I'm not a manager; I don't have any plans to become a manager. But one thing that she talks about early on is this idea of having a shared value system. And you can have that at the company level, right? You have your kind of corporate values. You can have that at the team level with this smaller group of people that you get to know better and kind of form relationships with. And then also, part of that is, like, knowing your individual values. And having alignment in all three of those tiers is really important in being a functioning and fulfilled team, I think. And that is something that I don't think was really spelled out very explicitly for me before, but it was helpful in framing, like, past work experiences, where maybe I, like, didn't have that alignment and now identify why. And it has helped me this year as I think about my client work, too, and kind of where I sit from that perspective and helps me realize like, oh, like, this is why I'm feeling this way, and this is why it's not quite working. And, like, what do I do about it now? So, I really enjoyed that. JOËL: Would you recommend this book to others who are maybe not considering a management path? STEPHANIE: Yeah. JOËL: So, even if you're staying in the IC track, at least for now, you think that's a really powerful book for other people. STEPHANIE: Yeah, I would say so. You know, maybe not, like, all of it, but there's definitely parts that, you know, she's writing for the rest of us, like, all of us maybe not necessarily natural born leaders who knew that that's kind of what we wanted. And so, I can see how people, you know, who are uncertain or maybe even, like, really clearly, like, "I don't think that's for me," being able to get something out of, like, either those lessons in leadership or just to feel a bit, like, validated [laughs] about the type of work that they aren't interested in. Another book that I want to plug real quick is Confident Ruby by Avdi Grimm. That one was one I referenced a lot this year, working with newer developers especially. And it actually provided a good heuristic [laughs] for me to talk about areas that we could improve code during code review. I think that wasn't really vocabulary that I'd used, you know, saying, like, "Hey, how confident is this code? How confident is this method and what it will receive and what it's returning?" And I remember, like, several conversations that I ended up having on my teams about, like, return types as a result and them having learned, like, a new way to view their code, and I thought that was really cool. JOËL: I mean, learning to deal with uncertainty and nil in Ruby or maybe even, like, error states is just such a core part of writing software. I feel like this is something that I almost wish everyone was sort of assigned maybe, like, a year into their programming career because, you know, I think the first year there's just so many things you've got to learn, right? Like basic programming and, like, all these things. But, like, you're looking maybe I can start going a little bit deeper into some topic. I think that some topic, like, pretty high up, would be building a mental model for how to deal with uncertainty because it's such a source of bugs. And Avdi Grimm's book, Confident Ruby, is...I would put that, yeah, definitely on a recommended reading list for everybody. STEPHANIE: Yeah, I agree. And I think that's why I found myself, you know, then recommending it to other people on my team and kind of having something I can point to. And that was really helpful in the kind of mentorship that I wanted to offer. JOËL: I did a deep dive into uncertainty and edge cases in programs several years back when I was getting into Elm. And I was giving a talk at Elm Europe about how Elm handles uncertainty, which is a little bit different than how Ruby does it. But a lot of the underlying concepts are very similar in terms of quarantining uncertainty and pushing it to the edges and things like that. Trying to write code that is more confident that is definitely a term that I used. And so Confident Ruby ended up being a little bit of an inspiration for my own journey there, and then, eventually, the talk that I gave that summarized my learnings there. STEPHANIE: Nice. Do you have any reading recommendations or books that stood out to you this year? JOËL: So, I've been reading two technical books kind of in tandem this year. I have not finished either of them, but I have been enjoying them. One is Sustainable Rails by David Bryant Copeland. We had an episode at the beginning of this year where we talked a little bit about our initial impressions from, I think, the first chapter of the book. But I really love that vocabulary of writing Ruby and Rails code, in particular, in a way that is sustainable for a team. And that premise, I think, just gives a really powerful mindset to approach structuring Rails apps. And the other book that I've been reading is Domain Modeling Made Functional, so kind of looking at some domain-driven design ideas. But most of the literature is typically written to an object-oriented audience, so taking a look at it from more of a functional programming perspective has been really interesting. And then I've been, weirdly enough, taking some of those ideas and translating back into the object-oriented world to apply to code I'm writing in Ruby. I think that has been a very useful exercise. STEPHANIE: That's awesome. And it's weird and cool how all those things end up converging, right? And exploring different paradigms really just lets you develop more insight into wherever you're working. JOËL: Sometimes the sort of conversion step that you have to do, that translation, can be a good tool for kind of solidifying learnings or better understanding. So, I'm doing this sort of deep learning thing where I'm taking notes as I go along. And those notes are typically around, what other concepts can I connect ideas in the book? So, I'll be reading and say, okay, on page 150, he mentioned this concept. This reminds me of this idea from TDD. I could see this applying in a different way in an object-oriented world. And interestingly, if you apply this, it sort of converges on maybe single responsibility or whatever other OO principle. And that's a really interesting connection. I always love it when you do see sort of two or three different angles converging together on the same idea. STEPHANIE: Yeah, absolutely. JOËL: I've written a blog post, I think, two years ago around how some theory from functional programming sort of OO best practices and then TDD all kind of converge on sort of the same approach to designing software. So, you can sort of go from either direction, and you kind of end in the same place or sort of end up rediscovering principles from the other two. We'll link that in the show notes. But that's something that I found was really exciting. It didn't directly come from this book because, again, I wrote this a couple of years ago. But it is always fun when you're exploring two or three different paradigms, and you find a convergence. It really deepens your understanding of what's happening. STEPHANIE: Yeah, absolutely. I like what you said about how this book is different because it is making that connection between things that maybe seem less related on the surface. Like you're saying, there's other literature written about how domain modeling and object-oriented programming make more sense a little bit more together. But it is that, like, bringing in of different schools of thought that can lead to a lot of really interesting discovery about those foundational concepts. JOËL: I feel like dabbling in other paradigms and in other languages has made me a better Ruby developer and a better OO programmer, a lot of the work I've done in Elm. This book that I'm reading is written in F#. And all these things I can kind of bring back, and I think, have made me a better Ruby developer. Have you had any experiences like that? STEPHANIE: Yeah. I think I've talked a little bit about it on the show before, but I can't exactly recall. There were times when my exploration in static typing ended up giving me that different mindset in terms of the next time I was coding in Ruby after being in TypeScript for a while, I was, like, thinking in types a lot more, and I think maybe swung a little bit towards, like, not wanting to metaprogram as much [laughs]. But I think that it was a useful, like you said, exercise sometimes, too, and just, like, doing that conversion or translating in your head to see more options available to you, and then deciding where to go from there. So, we've talked a bit about technical books that we've read. And now I kind of want to get into some in-person highlights for the year because you and I are both on the conference circuit and had some fun trips this year. JOËL: Yeah. So, I spoke at RailsConf this spring. I gave a talk on discrete math and how it is relevant in day-to-day work for developers, actually inspired by that Bike Shed episode that I mentioned earlier. So, that was kind of fun, turning a Bike Shed episode into a conference talk. And then just recently, I was at RubyConf in San Diego, and I gave a talk there around time. We often talk about time as a single quantity, but there's some subtle distinctions, so the difference between a moment in time versus a duration and some of the math that happens around that. And I gave a few sort of visual mental models to help people keep track of that. As of this recording, the talk is not out yet, so we're not going to be able to link to it. But if you're listening to this later in 2024, you can probably just Google RubyConf "Which Time Is It?" That's the name of the talk. And you'll be able to find it. STEPHANIE: Awesome. So, as someone who is giving talks and attending conferences every year, I'm wondering, was this year particularly different in any way? Was there something that you've, like, experienced or felt differently community-wise in 2023? JOËL: Conferences still feel a little bit smaller than they were pre-COVID. I think they are still bouncing back. But there's definitely an energy that's there that's nice to have on the conference scene. I don't know, have you experienced something similar? STEPHANIE: I think I know what you're talking about where, you know, there was that time when we weren't really meeting in person. And so, now we're still kind of riding that wave of, like, getting together again and being able to celebrate and have fun in that way. I, this year, got to speak at Blue Ridge Ruby in June. And that was a first-time regional conference. And so, that was, I think, something I had noticed, too, is the emergence of regional conferences as being more viable options after not having conferences for a few years. And as a regional conference, it was even smaller than the bigger national Ruby Central conferences. I really enjoyed the intimacy of that, where it was just a single track. So, everyone was watching talks together and then was on breaks together, so you could mingle. There was no FOMO of like, oh, like, I can't make this talk because I want to watch this other one. And that was kind of nice because I could, like, ask anyone, "What did you think of, like, X talk or like the one that we just kind of came out of and had that shared experience?" That was really great. And I got to go tubing for the first time [laughs] in Asheville. That's a memory, but I am still thinking about that as we get into winter. I'm like, oh yeah, the glorious days of summer [laughs] when I was getting to float down a lazy river. JOËL: Nice. I wasn't sure if this was floating down a lazy river on an inner tube or if this was someone takes you out on a lake with a speed boat, and you're getting pulled. STEPHANIE: [laughs] That's true. As a person who likes to relax [laughs], I definitely prefer that kind of tubing over a speed boat [laughs]. JOËL: What was the topic of your talk? STEPHANIE: So, I got to give my talk about nonviolent communication in pair programming for a second time. And that was also my first time giving a talk for a second time [laughs]. That was cool, too, because I got to revisit something and go deeper and kind of integrate even more experiences I had. I just kind of realized that even if you produce content once, like, there's always ways to deepen it or shape it a little better, kind of, you know, just continually improving it and as you learn more and as you get more experience and change. JOËL: Yeah. I've never given a talk twice, and now you've got me wondering if that's something I should do. Because making a bespoke talk for every conference is a lot of work, and it might be nice to be able to use it more than once. Especially I think for some of the regional conferences, there might be some value there in people who might not be able to go to a big national conference but would still like to see your talk live. Having a mix of maybe original content and then content that is sort of being reshared is probably a great combo for a regional conference. STEPHANIE: Yeah, definitely. That's actually a really good idea, yeah, to just be able to have more people see that content and access it. I like that a lot. And I think it could be really cool for you because we were just talking about all the ways that our mental models evolve the more stuff that we read and consume. And I think there's a lot of value there. One other conference that I went to this year that I just want to highlight because it was really cool that I got to do this: I went to RubyKaigi in Japan [laughs] back in the spring. And I had never gone to an international conference before, and now I'm itching to do more of that. So, it would be remiss not to mention it [laughs]. I'm definitely inspired to maybe check out some of the conferences outside of the U.S. in 2024. I think I had always been a little intimidated. I was like, oh, like, it's so far [laughs]. Do I really have, like, that good of a reason to make a trip out there? But being able to meet Rubyists from different countries and seeing how it's being used in other parts of the world, I think, made me realize that like, oh yeah, like, beyond my little bubble, there's so many cool things happening and people out there who, again, like, have that shared love of Ruby. And connecting with them was, yeah, just so new and something that I would want to do more of. So, another thing that we haven't yet gotten into is our actual work-work or our client work [laughs] that we do at thoughtbot for this year. Joël, I'm wondering, was there anything especially fun or anything that really stood out to you in terms of client work that you had to do this year? JOËL: So, two things come to mind that were novel for me. One is I did a Rails integration against Snowflake, the data warehouse, using an ODBC connection. We're not going through an API; we're going through this DB connection. And I never had to do that before. I also got to work with the new-ish Rails multi-database support, which actually worked quite nice. That was, I think, a great learning experience. Definitely ran into some weird edge cases, or some days, I was really frustrated. Some days, I was actually, like, digging into the source code of the C bindings of the ODBC gem. Those were not the best days. But definitely, I think, that kind of integration and then Snowflake as a technology was really interesting to explore. The other one that's been really interesting, I think, has been going much deeper into the single sign-on world. I've been doing an integration against a kind of enterprise SAML server that wants to initiate sign-in requests from their portal. And this is a bit of an alphabet soup, but the term here is IdP-initiated SSO. And so, I've been working with...it's a combination of this third-party kind of corporate SAML system, our application, which is a Rails app, and then Auth0 kind of sitting in the middle and getting all of them to talk to each other. There's a ridiculous number of redirects because we're talking SAML on one side and OIDC on the other and getting everything to line up correctly. But that's been a really fun, new set of things to learn. STEPHANIE: Yeah, that does sound complicated [laughs] just based on what you shared with me, but very cool. And I was excited to hear that you had had a good experience with the Rails multi-database part because that was another thing that I remember being...it had piqued my interest when it first came out. I hope I get to, you know, utilize that feature on a project soon because that sounds really fun. JOËL: One thing I've had to do for this SSO project is lean a lot on sequence diagrams, which are those diagrams that sort of show you, like, being redirected from different places, and, like, okay, server one talks to server two talks, to the browser. And so, when I've got so many different actors and sort of controllers being passed around everywhere, it's been hard to keep track of it in my head. And so, I've been doing a lot of these diagrams, both for myself to help understand it during development, and then also as documentation to share back with the team. And I found that Mermaid.js supports sequence diagrams as a diagram type. Long-term listeners of the show will know that I am a sucker for a good diagram. I love using Mermaid for a lot of things because it's supported. You can embed it in a lot of places, including in GitHub comments, pull requests. You can use it in various note systems like Notion or Obsidian. And you can also just generate your own on mermaid.live. And so, that's been really helpful to communicate with the rest of the team, like, "Hey, we've got this whole process where we've got 14 redirects across four different servers. Here's what it looks like. And here, like, we're getting a bug on, you know, redirect number 8 of 14. I wonder why," and then you can start a conversation around debugging that. STEPHANIE: Cool. I was just about to ask what tool you're using to generate your sequence diagrams. I didn't know that Mermaid supported them. So, that's really neat. JOËL: So, last year, when we kind of looked back over 2022, one thing that was really interesting that we did is we talked about what are articles that you find yourself linking to a lot that are just kind of things that maybe were on your mind or that were a big part of conversations that happened over the year? So, maybe for you, Stephanie, in 2023, what are one or two articles that you find yourself sort of constantly linking to other people? STEPHANIE: Yes. I'm excited you asked about this. One of them is an article by a person named Cat Hicks, who has a PhD in experimental psychology. She's a data scientist and social scientist. And lately, she's been doing a lot of research into the sense of belonging on software teams. And I think that's a theme that I am personally really interested in, and I think has kind of been something more people are talking about in the last few years. And she is kind of taking that maybe more squishy idea and getting numbers for it and getting statistics, and I think that's really cool. She points out belonging as, like, a different experience from just, like, happiness and fulfillment, and that really having an impact on how well a team is functioning. I got to share this with a few people who were, you know, just in that same boat of, like, trying to figure out, what are the behaviors kind of on my team that make me feel supported or not supported? And there were a lot of interesting discussions that came out of sharing this article and kind of talking about, especially in software, where we can be a little bit dogmatic. And we've kind of actually joked about it on the podcast [chuckles] before about, like, we TDD or don't TDD, or, you know, we use X tool, and that's just like what we have to do here. She writes a little bit about how that can end up, you know, not encouraging people offering, like, differing opinions and being able to feel like they have a say in kind of, like, the team's direction. And yeah, I just really enjoyed a different way of thinking about it. Joël, what about you? What are some articles you got bookmarked? [chuckles] JOËL: This year, I started using a bookmark manager, Raindrop.io. That's been nice because, for this episode, I could just look back on, what are some of my bookmarks this year? And be like, oh yeah, this is the thing that I have been using a lot. So, an article that I've been linking is an article called Preemptive Pluralization is (Probably) Not Evil. And it kind of talks a little bit about how going from code that works over a collection of two items to a collection of, you know, 20 items is very easy. But sometimes, going from one to two can be really challenging. And when are the times where you might want to preemptively make something more than one item? So, maybe using it has many association rather than it has one or making an attribute a collection rather than a single item. Controversial is not the word for it, but I think challenges a little bit of the way people typically like to write code. But across this year, I've run into multiple projects where they have been transitioning from one to many. That's been an interesting article to surface as part of those conversations. Whether your team wants to do this preemptively or whether they want to put it off and say in classic YAGNI (You Aren't Gonna Need It) form, "We'll make it single for now, and then we'll go plural," that's a conversation for your team. But I think this article is a great way to maybe frame the conversation. STEPHANIE: Cool. Yeah, I really like that almost, like, a counterpoint to YAGNI [laughs], which I don't think I've ever heard anyone say that out loud [laughs] before. But as soon as you said preemptive pluralization is not evil, I thought about all the times that I've had to, like, write code, text in which a thing, a variable could be either one or many [laughs] things. And I was like, ooh, maybe this will solve that problem for me [laughs]. JOËL: Speaking of pluralization, I'm sure you've been linking to more than just one article this year. Do you have another one that you find yourself coming up in conversations where you've always kind of like, "Hey, dropping this link," where it's almost like your thing? STEPHANIE: Yes. And that is basically everything written by Mandy Brown [laughs], who is a work coach that I actually started working with this year. And one of the articles that really inspired me or really has been a topic of conversation among my friends and co-workers is she has a blog post called Digging Through the Ashes. And it's kind of a meditation on, like, post burnout or, like, what's next, and how we have used this word as kind of a catch-all to describe, you know, this collective sense of being just really tired or demoralized or just, like, in need of a break. And what she offers in that post is kind of, like, some suggestions about, like, how can we be more specific here and really, you know, identify what it is that you're needing so that you can change how you engage with work? Because burnout can mean just that you are bored. It can mean that you are overworked. It can mean a lot of things for different people, right? And so, I definitely don't think I'm alone [laughs] in kind of having to realize that, like, oh, these are the ways that my work is or isn't changing and, like, where do I want to go next so that I might feel more sustainable? I know that's, like, a keyword that we talked about earlier, too. And that, on one hand, is both personal but also technical, right? It, like, informs the kinds of decisions that we make around our codebase and what we are optimizing for. And yeah, it is both technical and cultural. And it's been a big theme for me this year [laughs]. JOËL: Yeah. Would you say it's safe to say that sustainability would be, if you want to, like, put a single word on your theme for the year? Would that be a fair word to put there? STEPHANIE: Yeah, I think so. Definitely discovering what that means for me and helping other people discover what that means for them, too. JOËL: I feel like we kicked off the year 2023 by having that discussion of Sustainable Rails and how different technical practices can make the work there feel sustainable. So, I think that seems to have really carried through as a theme through the year for you. So, that's really cool to have seen that. And I'm sure listeners throughout the year have heard you mention these different books and articles. Maybe you've also been able to pick up a little bit on that. So, I'm glad that we do this show because you get a little bit of, like, all the bits and pieces in the day-to-day, and then we aggregate it over a year, and you can look back. You can be like, "Oh yeah, I definitely see that theme in your work." STEPHANIE: Yeah, I'm glad you pointed that out. It is actually really interesting to see how something that we had talked about early, early on just had that thread throughout the year. And speaking of sustainability, we are taking a little break from the show to enjoy the holidays. We'll be off for a few weeks, and we will be back with a new Bike Shed in January. JOËL: Cheers to a new year. STEPHANIE: Yeah, cheers to a new year. Wrapping up 2023. And we will see you all in 2024. JOËL: On that note, shall we wrap up the whole year? STEPHANIE: Let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeee!!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at tbot.io/ referral. Or you can email us at referrals@thoughtbot.com with any questions.
Joël shares his experiences with handling JSON in a Postgres database. He talks about his challenges with ActiveRecord and JSONB columns, particularly the unexpected behavior of storing and retrieving JSON data. Stephanie shares her recent discovery of bookmarklets and highlights a bookmarklet named "Check This Out," which streamlines searching for books on Libby, an ebook and audiobook lending app. The conversation shifts to using constants in code as a form of documentation. Stephanie and Joël discuss how constants might not always accurately reflect current system behavior or logic, leading to potential misunderstandings and the importance of maintaining accurate documentation. Bookmarklets (https://www.freecodecamp.org/news/what-are-bookmarklets/) "Check This Out" Bookmarklet (https://checkthisout.today/) Libby (https://libbyapp.com/interview/welcome#doYouHaveACard) Productivity Tricks (https://www.bikeshed.fm/403) 12 Factor App Config (https://12factor.net/config) A Hierarchy of Documentation (https://challahscript.com/hiearchy_of_documentation) Sustainable Rails (https://sustainable-rails.com/) rails-erd gem (https://github.com/voormedia/rails-erd) Transcript STEPHANIE: Hello and welcome to another episode of the Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: What's new in my world is JSON and how to deal with it in a Postgres database. So, I'm dealing with a situation where I have an ActiveRecord model, and one of the columns is a JSONB column. And, you know, ActiveRecord is really nice. You can just throw a bunch of different data at it, and it knows the column type, and it will do some conversions for you automatically. So, if I'm submitting a form and, you know, form values might come in as strings because, you know, I typed in a number in a text field, but ActiveRecord will automatically parse that into an integer because it knows we're saving that to an integer column. So, I don't need to do all these, like, manual conversions. Well, I have a form that has a string of JSON in it that I'm trying to save in a JSONB column. And I expected ActiveRecord to just parse that into a hash and store it in Postgres. That is not what happens. It just stores a raw string, so when I pull it out again, I don't have a hash. I have a raw string that I need to deal with. And I can't query it because, again, it is a raw string. So, that was a bit of an unexpected behavior that I saw there. STEPHANIE: Yeah, that is unexpected. So, is this a field that has been used for a while now? I'm kind of surprised that there hasn't been already some implementations for, like, deserializing it. JOËL: So, here's the thing: I don't think you can have an automatic deserialization there because there's no way of knowing whether or not you should be deserializing. The reason is that JSON is not just objects or, in Ruby parlance, hashes. You can also have arrays. But just raw numbers not wrapped in hashes are also valid JSON as are raw strings. And if I just give you a string and say, put this in a JSON field, you have no way of knowing, is this some serialized JSON that you need to deserialize and then save? Or is it just a string that you should save because strings are already JSON? So, that's kind of on you as the programmer to make that distinction because you can't tell at runtime which one of these it is. STEPHANIE: Yeah, you're right. I just realized it's [laughs] kind of, like, an anything goes [laughs] situation, not anything but strings are JSON, are valid JSON, yep [laughs]. That sounds like one of those things that's, like, not what you think about immediately when dealing with that kind of data structure, but... JOËL: Right. So, the idea that strings are valid JSON values, but also all JSON values can get serialized as strings. And so, you never know: are you dealing with an unserialized string that's just a JSON value, or are you dealing with some JSON blob that got serialized into a string? And only in one of those do you want to then serialize before writing into the database. STEPHANIE: So, have you come to a solution or a way to make your problem work? JOËL: So, the solution that I did is just calling a JSON parse before setting that attribute on my model because this value is coming in from a form. I believe I'm doing this when I'm defining the strong parameters for that particular form. I'm also transforming that string by parsing it into a hash with the JSON dot parse, which then gets passed to the model. And then I'm not sure what JSONB serializes as under the hood. When you give it a hash, it might store it as a string, but it might also have some kind of binary format or some internal AST that it uses for storage. I'm not sure what the implementation is. STEPHANIE: Are the values in the JSONB something that can be variable or dynamic? I've seen some people, you know, put that in getter so that it's just kind of done for you for anyone who needs to access that field. JOËL: Right now, there is a sort of semi-consistent schema to that. I think it will probably evolve to where I'll pull some of these out to be columns on the table. But it is right now kind of an everything else sort of dumping ground from an API. STEPHANIE: Yeah, that's okay, too, sometimes [laughs]. JOËL: Yeah. So, interesting journey into some of the fun edge cases of dealing with a format whose serialized form is also a valid instance of that format. What's been new in your world? STEPHANIE: So, I discovered something new that has been around on the internet for a while, but I just haven't been aware of it. Do you know what a bookmarklet is? JOËL: Oh, like a JavaScript code that runs in a bookmark? STEPHANIE: Yeah, exactly. So, you know, in your little browser bookmark where you might normally put a URL, you can actually stick some JavaScript in there. And it will run whenever you click your bookmark in your browser [chuckles]. So, that was a fun little internet tidbit that I just found out about. And the reason is because I stumbled upon a bookmarklet made by someone. It's called Check This Out. And what it does is there's another app/website called Libby that is used to check out ebooks and audiobooks for free from your local public library. And what this Check This Out bookmarklet does is you can kind of select any just, like, text on a web page, and then when you click the bookmarklet, it then just kind of sticks it into the query params for Libby's search engine. And it takes you straight to the results for that book or that author, and it saves you a few extra manual steps to go from finding out about a book to checking it out. So, that was really neat and cute. And I was really surprised that you could do that. I was like, whoa [laughs]. At first, I was like, is this okay? [laughs] If you, like, you can't read, you know, you don't know what the JavaScript is doing, I can see it being a little sketchy. But –- JOËL: Be careful of executing arbitrary JavaScript. STEPHANIE: Yeah, yeah. When I did look up bookmarklets, though, I kind of saw that it was, you know, just kind of a fun thing for people who might be learning to code for the first time to play around with. And some fun ideas they had for what you could do with it was turning all the font on a web page to Comic Sans [laughs]. So yeah, I thought that was really cute. JOËL: Has that inspired you to write your own? STEPHANIE: Well, we did an episode a while ago on productivity tricks. And I was thinking like, oh yeah, there's definitely some things that I could do to, you know, just stick some automated tasks that I have into a bookmarklet. And that could be a really fun kind of, like, old-school way of doing it, as opposed to, you know, coding my little snippets or getting into a new, like, Omnibar app [laughs]. JOËL: So, something that is maybe a little bit less effort than building yourself a browser extension or something like that. STEPHANIE: Yeah, exactly. JOËL: I had a client project once that involved a...I think it was, like, a five-step wizard or something like that. It was really tedious to step through it all to manually test things. And so, I wrote a bookmarklet that would just go through and fill out all the fields and hit submit on, like, five pages worth of these things. And if anything didn't work, it would just pause there, and then you could see it. In some way, it was moving towards the direction of, like, an automated like Capybara style test. But this was something that was helping for manual QA. So, that was a really fun use of a bookmarklet. STEPHANIE: Yeah, I like that. Like, just an in-between thing you could try to speed up that manual testing without getting into, like you said, an automated test framework for your browser. JOËL: The nice thing about that is that this could be used without having to set up pretty much anything, right? You paste a bit of JavaScript into your bookmark bar, and then you just click the button. That's all you need to do. No need to make sure that you've got Ruby installed on your machine or any of these other things that you would need for some kind of testing framework. You don't need Selenium. You don't need ChromeDriver. It just...it works. So, I was working...this was a greenfield startup project. So, I was working with a non-technical founder who didn't have all these things, you know, dev tooling on his machine. So, he wanted to try out things but not spend his days filling out forms. And so, having just a button he could click was a really nice shortcut. STEPHANIE: That's really cool. I like that a lot. I wasn't even thinking about how I might be able to bring that in more into just my daily work, as opposed to just something kind of fun. But that's an awesome idea. And I hope that maybe I'll have a good use for one in the future. JOËL: It feels like the thing that has a lot of potential, and yet I have not since written...I don't think I've written any bookmarklets for myself. It feels like it's the kind of thing where I should be able to do this for all sorts of fun tooling and just automate my life away. Somehow, I haven't done that. STEPHANIE: Bring back the bookmarklet [laughs]. That's what I have to say. JOËL: So, I mentioned earlier that I was working with a JSONB column and storing JSON on an ActiveRecord model. And then I wanted to interact with it, but the problem is that this JSON is somewhat arbitrary, and there are a lot of magic strings in there. All of the key names might change. And I was really concerned that if the schema of that JSON ever changed, if we changed some of the key names or something like that, we might accidentally break code in multiple parts of the app. So, I was very careful while building that model to quarantine any references to any raw strings only within that model, which meant that I leaned really heavily on constants. And, in some way, those constants end up kind of documenting what we think the schema of that JSON should be. And that got me thinking; you were telling me recently about a scenario where some code you were working with relied heavily on constants as a form of documentation, and that documentation kind of lied to you. STEPHANIE: Yeah, it did. And I think you mentioned something that I wanted to point out, which is that the magic strings that you think might change, and you wanted to pull that out into a constant, you know, so at least it's kind of defined in one place. And if it ever does change, you know, you don't have to change it in all of those places. And I do think that, normally, you know, if there's opportunities to extract those magic strings and give a name to them, that is beneficial. But I was gripping a little bit about when constants become, I guess, like, too wieldy, or there's just kind of, like, too much of a dependency on them as the things documenting how the app should work when it's constantly changing. I realized that I just used constant and constantly [laughs]. JOËL: The only constant is that it is not constant. STEPHANIE: Right. And so, the situation that I found myself in—this was on a client project a little bit ago—was that the constants became, like, gatekeepers of that logic where dev had to change it if the app's behavior changed, and maybe we wanted to change the value of it. And also, one thing that I noticed a lot was that we, as developers, were getting questions about, "Hey, like, how does this actually work?" Like, we were using the constants for things like pricing of products, for things like what is a compatible version for this feature. And because that was only documented in the code, other people who didn't have access to it actually were left in the dark. And because those were changing with somewhat frequency, I was just kind of realizing how that was no longer working for us. JOËL: Would you say that some of these values that we stored as constants were almost more like config rather than constants or maybe they're just straight-up application data? I can imagine something like price of an item you probably want that to be a value in the database that can be updated by an admin. And some of these other things maybe are more like config that you change through some kind of environment variable or something like that. STEPHANIE: Yeah, that's a good point. I do think that they evolved to become things that needed to be configured, right? I suppose maybe there wasn't as much information or foresight at the beginning of like, oh, this is something that we expect to change. But, you know, kind of when you're doing that first pass and you're told, like, hey, like, this value should be the price of something, or, like, the duration of something, or whatever that may be. It gets codified [chuckles]. And there is some amount of lift to change it from something that is, at first, just really just documenting what that decision was at the time to something that ends up evolving. JOËL: How would you draw a distinction between something that should be a constant versus something that maybe would be considered config or some other kind of value? Because it's pretty easy, right? As developers, we see magic numbers. We see magic strings. And our first thought is, oh, we've seen this problem before—constant. Do you have maybe a personal heuristic for when to reach for a constant versus when to reach for something else? STEPHANIE: Yeah, that's a good question. I think when I started to see it a lot was especially when the constants were arrays or hashes [laughs]. And I guess that is actually kind of a signal, right? You will likely be adding more stuff [laughs] into that data structure [laughs]. And, again, like, maybe it's okay, like, the first couple of times. But once you're seeing that request happen more frequently, that could be a good way to advocate for storing it in the database or, like, building a lightweight admin kind of thing so that people outside of the dev team can make those configuration changes. I think also just asking, right? Hey, like, how often do we suspect this will change? Or what's on the horizon for the product or the team where we might want to introduce a way to make the implementation a bit more flexible to something that, you know, we think we know now, but we might want to adjust for? JOËL: So, it's really about change and how much we think this might change in the future. STEPHANIE: Speaking of change, this actually kind of gets into the broader topic of documentation and how to document a changing and evolving entity [chuckles], you know, that being, like, the codebase or the way that decisions are made that impact how an application works. And you had shared, in preparation for this topic, an article that I read and enjoyed called Hierarchy of Documentation. And one thing that I liked about it is that it kind of presented all of the places that you could put information from, you know, straight in the code, to in your commit messages, to your issue management system, and to even wikis for your repo or your team. And I think that's actually something that we would want to share with new developers, you know, who might be wondering, like, where do I find or even put information? I really liked how it was kind of, like, laid out and gave, like, different reasons for where you might want to put something or not. JOËL: We think a lot about documentation as code writers. I'm curious what your experience is as a code reader. How do you tend to try to read code and understand documentation about how code works? And, apparently, the answer is, don't read the constants because these constants lie. STEPHANIE: I think you are onto something, though, because I was just thinking about how distrustful I've become of certain types of documentation. Like, when I think of code comments, on one hand, they should be a signal, right? They should kind of draw your attention to something maybe weird or just, like, something to note about the code that it's commenting on, or where it's kind of located in a file. But I sometimes tune them out, I'm not going to lie. When I see a really big block of code [chuckles] comment, I'm like, ugh, like, do I really have to read all of this? I'm also not positive that it's still relevant to the code below it, right? Like, I don't always have git blame, like, visually enabled in my editor. But oftentimes, when I do a little bit of digging, that comment is left over from maybe when that code was initially introduced. But, man, there have been lots of commits [chuckles] in the corresponding, you know, like, function sense, and I'm not really sure how relevant it is anymore. Do you struggle with the signal versus noise issue with code comments? How much do you trust them, and how much do you kind of, like, give credence to them? JOËL: I think I do tend to trust them with maybe some slight skepticism. It really depends on the codebase. Some codebases are really bad sort of comment hygiene and just the types of comments that they put in there, and then others are pretty good at it. The ones that I tend to particularly appreciate are where you have maybe some, like, weird function and you're like, what is going on here? And then you've got a nice, little paragraph up top explaining what's going on there, or maybe an explanation of ways you might be tempted to modify that piece of code and, like, why it is the way it is. So, like, hey, you might be wanting to add an extra branch here to cover this edge case. Don't do that. We tried it, and it causes problems for XY reasons. And sometimes it might be, like, a performance thing where you say, look, the code quality person in you is going to look at this and say, hey, this is hard to read. It would be better if we did this more kind of normalized form. Know that we've particularly written this in a way that's hard to read because it is more performant, and here are the numbers. This is why we want it in this way. Here's a link to maybe the issue, or the commit, or whatever where this happened. And then if you want to start that discussion up again and say, "Hey, do we really need performance here at the cost of readability?", you can start it up again. But at least you're not going to just be like, oh, while I'm here, I'm going to clean up this messy code and accidentally cause a regression. STEPHANIE: Yeah. I like what you said about comment hygiene being definitely just kind of, like, variable depending on the culture and the codebase. JOËL: I feel like, for myself, I used to be pretty far on the spectrum of no comments. If I feel the need to write a comment, that's a smell. I should find other ways to communicate that information. And I think I went pretty far down that extreme, and then I've been slowly kind of coming back. And I've probably kind of passed the center, where now I'm, like, slightly leaning towards comments are actually nice sometimes. And they are now a part of my toolkit. So, we'll see if I keep going there. Maybe I'll hit some point where I realize that I'm putting too much work into comments or comments are not being helpful, and I need to come back towards the center again and focus on other ways of communicating. But right now, I'm in that phase of doing more comments than I used to. How about you? Where do you stand on that sort of spectrum of all information should be communicated in code tokens versus comments? STEPHANIE: Yeah, I think I'm also somewhere in the middle. I think I have developed an intuition of when it feels useful, right? In my gut, I'm like, oh, I'm doing something weird. I wish I didn't have to do this [chuckles]. I think it's another kind of intuition that I have now. I might leave a comment about why, and I think that is more of that signal, right? Though I also recently have been using them more as just, like, personal notes for myself as I'm, you know, in my normal development workflow, and then I will end up cleaning them up later. I was working on a codebase where there was a soft delete functionality. And that was just, like, a concern that was included in some of the models. And I didn't realize that that's what was going on. So, when I, you know, I was calling destroy, I thought it was actually being deleted, and it turns out it wasn't. And so, that was when I left a little comment for myself that was like, "Hey, like, this is soft deleted." And some of those things I do end up leaving if I'm like, yes, other people won't have the same context as me. And then if it's something that, like, well, people who work in this app should know that they have soft delete, so then I'll go ahead and clean that up, even though it had been useful for me at the time. JOËL: Do you capture that information and then put it somewhere else then? Or is it just it was useful for you as a stepping-stone on the journey but then you don't need it at the end and nobody else needs to care about it? STEPHANIE: Oh, you know what? That's actually a really great point. I don't think I had considered saving that information. I had only thought about it as, you know, just stuff for me in this particular moment in time. But that would be really great information to pull out and put somewhere else [chuckles], perhaps in something like a wiki, or like a README, or somewhere that documents things about the system as a whole. Yeah, should we get into how to document kind of, like, bigger-picture stuff? JOËL: How do you feel about wikis? Because I feel like I've got a bit of a love-hate relationship with them. STEPHANIE: I've seen a couple of different flavors of them, right? Sometimes you have your GitHub wiki. Sometimes you have your Confluence ecosystem [laughs]. I have found that they work better if they're smaller [laughs], where you can actually, like, navigate them pretty well, and you have a sense of what is in there, as opposed to it just being this huge knowledge base that ends up actually, I think, working against you a little bit [laughs]. Because so much information gets duplicated if it's hard to find and people start contributing to it maybe without keeping in mind, like, the audience, right? I've seen a lot of people putting in, like, their own personal little scripts [laughs] in a wiki, and it works for them but then doesn't end up working for really anyone else. What's your love-hate relationship to them? JOËL: I think it's similar to what you were saying, a little bit of structure is nice. When they've just become dumping grounds of information that is maybe not up to date because over the course of several years, you end up with a lot of maybe conflicting articles, and you don't know which one is the right thing to do, it becomes hard to find things. So, when it just becomes a dumping ground for random information related to the company or the app, sometimes it becomes really challenging to find the information I need and to find information that's relevant, to the point where oftentimes looking something up in the wiki is my last resort. Like, I'm hoping I will find the answer to my question elsewhere and only fallback to the wiki if I can't. STEPHANIE: Yeah, that's, like, the sign that the wiki is really not trustworthy. And it kind of is diminishing returns from there a bit. I think I fell into this experience on my last project where it was a really, really big wiki for a really big codebase for a lot of developers. And there was kind of a bit of a tragedy of the commons situation, where on one hand, there were some things that were so manual that the steps needed to be very explicitly documented, but then they didn't work a lot of the time [laughs]. But it was hard to tell if they weren't working for you or because it was genuinely something wrong with, like, the way the documentation laid out the steps. And it was kind of like, well, I'm going to fix it for myself, but I don't know how to fix it for everyone else. So, I don't feel confident in updating this information. JOËL: I think that's what's really nice about the article that you mentioned about the hierarchy of documentation. It's that all of these different forms—code, comments, commit messages, pull requests, wikis—they don't have to be mutually exclusive. But sometimes they work sort of in addition to each other sort of each adding more context. But also, sometimes it's you sort of choose the one that's the highest up on that list that makes sense for what you're trying to do, so something like documenting a series of steps to do something maybe a wiki is a good place for that. But maybe it's better to have that be executable. Could that be a script somewhere? And then maybe that can be a thing that is almost, like, living documentation, but also where you don't need to maybe even think about the individual steps anymore because the script is running, you know, 10 different things. And I think that's something that I really appreciated from the book Sustainable Rails is there's a whole section there talking about the value of setup scripts and how people who are getting started on your app don't want to have to care about all the different things to set it up, just run a script. And also, that becomes living documentation for what the app needs, as opposed to maybe having a bulleted list with 10 elements in it in your project README. STEPHANIE: Yeah, absolutely. In the vein of living documentation, I think one thing that wikis can be kind of nice for is for putting visual supplements. So, I've seen them have, like, really great graphs. But at the same time, you could use a gem like Rails-ERD that generates the entity relationship diagram as the schema of your database changes, right? So, it's always up to date. I've seen that work well, too, when you want to have, like I said, those, like, system-level documentation that sometimes they do change frequently and, you know, sometimes they don't. But that's definitely worth keeping in mind when you choose, like, how you want to have that exist as information. JOËL: How do you feel about deleting documentation? Because I feel like we put so much work into writing documentation, kind of like we do when writing tests. It feels like more is always better. Do you ever go back and maybe sort of prune some of your docs, or try to delete some things that you think might no longer be relevant or helpful? STEPHANIE: I was also thinking of tests when you first posed that question. I don't know if I have it in my practice to, like, set aside time and be like, hmm, like, what looks outdated these days? I am starting to feel more confident in deleting things as I come across them if I'm like, I just completely ignored this or, like, this was just straight up wrong [laughs]. You know, that can be scary at first when you aren't sure if you can make that determination. But rather than thrust that, you know, someone else going through that same process of spending time, you know, trying to think about if this information was useful or not, you can just delete it [laughs]. You can just delete tests that have been skipped for months because they don't work. Like, you can delete information that's just no longer relevant and, in some ways, causing you more pain because they are cluttering up your wiki ecosystem so that no one [laughs] feels that any of that information is relevant anymore. JOËL: I'll be honest, I don't think I've ever deleted a wiki article that was out of date or no longer relevant. I think probably the most I've done is go to Slack and complain about how an out-of-date wiki page led me down the wrong path, which is probably not the most productive way to channel those feelings. So, maybe I should have just gone back and deleted the wiki page. STEPHANIE: I do like to give a heads up, I think. It's like, "Hey, I want to delete this thing. Are there any qualms?" And if no one on your team can see a reason to keep it and you feel good about that it's not really, like, serving its purpose, I don't know, maybe consider just doing it. JOËL: To kind of wrap up this topic, I've got a spicy question for you. STEPHANIE: Okay, I'm ready. JOËL: Do you think that AI is going to radically change the way that we interact with documentation? Imagine you have an LLM that you train on maybe not just your code but the Git history. It has all the Git comments and maybe your wiki. And then, you can just ask it, "Why does function foo do this thing?" And it will reference a commit message or find the correct wiki article. Do you think that's the future of understanding codebases? STEPHANIE: I don't know. I'm aware that some people kind of can see that as a use case for LLMs, but I think I'm still a little bit nervous about the not knowing how they got there kind of part of it where, you know, yes, like I am doing this manual labor of trying to sort out, like, is this information good or trustworthy or not? But at least that is something I'm determining for myself. So, that is where my skepticism comes in a little bit. But I also haven't really seen what it can do yet or seen the outcomes of it. So, that's kind of where I'm at right now. JOËL: So, you think, for you, the sort of the journey of trying to find and understand the documentation is a sort of necessary part of building the understanding of what the code is doing. STEPHANIE: I think it can be. Also, I don't know, maybe my life would be better by having all that cut out for me, or I could be burned by it because it turns out that it was bad information [laughs]. So, I can't say for sure. On that note, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at: tbot.io/referral. Or you can email us at: referrals@thoughtbot.com with any questions.
Stephanie recommends "Blue Eye Samurai" and a new ceramic pot (donabe) for cooking. Joël talks about the joy of holding a warm beverage in a unique mug. Stephanie discusses her shift to a part-time support and maintenance role at thoughtbot, contrasting it with her full-time development work. She highlights the importance of communication, documentation, and workplace flexibility in this role. Stephanie appreciates the professional growth opportunities and aligns this flexible work style with her long-term career goals. Blue Eye Samurai (https://www.netflix.com/title/81144203) Donabe pots (https://jinenstore.com/collections/nagatani-en) thoughtbot's Support & Maintenance services (https://thoughtbot.com/services/rails-maintenance) Transcript: JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. STEPHANIE: And I'm Stephanie Minn. And together, we're here to share a bit of what we've learned along the way. JOËL: So, Stephanie, what's new in your world? STEPHANIE: I have a TV show recommendation this week. I think this is my first time having TV or movies to recommend, so this will be fun. My partner and I just finished watching Blue Eye Samurai on Netflix, which is an animated historical Samurai drama. But the really cool thing about it is that the protagonist she's a woman who is disguising herself as a man, and she is half Japanese and half White, which the show takes place during Edo, Japan. And so that was a time when Japan was locked down, and there were no outsiders allowed in the country. And so, to be mixed race like that was to be, like, kind of, like, demonized and to be really excluded and shamed. And so, the main character is on, like, a revenge mission. And it was such a cool show. I was kind of, like, on the edge of my seat the whole time. And it's very beautifully animated. There were just a lot of really awesome things about it. And I think it's very different from what I've been seeing on TV these days. JOËL: Is this a single-season show? STEPHANIE: So far, there's just one season. I think it's pretty new, yeah. It's very watchable in a couple of weekends. [laughter] JOËL: Dangerously so. STEPHANIE: Yeah, exactly [laughs]. JOËL: How do you feel about the way they end the arc in season one? Do they kind of leave you on a cliffhanger, or does it feel like a pretty satisfying place? STEPHANIE: Ooh, I think both, which is the sweet spot, in my opinion, where it's not, like, cliffhanger for the sake of, like, ugh, now I feel like I have to just watch the next part to see what happens because I was left unsatisfied. I like when seasons are kind of like chapters of the story, right? And the characters are also well written, too, and really fleshed out even, you know, some of the side characters. They all have their arcs that are really satisfying. And, again, I just was left very impressed. JOËL: I guess that's the power of good storytelling. STEPHANIE: Yeah. I was reading a review of the show. And that was kind of the theme of–it was just that, like, this is really good storytelling, and I would have to agree. Yeah, I highly recommend checking it out. It was very fun. It was very bloody, but [chuckles], for me, it being animated actually made it a little more palatable for me [laughs]. The fight scenes, the action scenes were really cool. I think the way that it's been described is kind of, like, you know, if you like historical dramas, or if you like things like Game of Thrones, there's kind of something for everyone. I recommend checking it out. Joël, what's new in your world? JOËL: Listeners of the show don't know this, but you and I are on a video call while we're recording this. And you'd commented earlier that I was holding a cool mug. It's got a rock climbing hold as a handle, which is pretty fun. I enjoy a lot of bouldering. That makes it a fun mug. But I was recently thinking about just how much pleasure I get from holding a mug with a warm beverage. It's such a small thing, but it makes me so happy. And that got me thinking more broadly about what are things in life that are kind of like that. They're small things that have, like, an outsized impact on your happiness. Do you have anything like that? STEPHANIE: Oh yes, absolutely. You were talking about the warmth of a hot beverage in your hands. And I was thinking about something similar, too, because I'm pretty sure this time of year last year, I talked about something that was new in my world that was just, like, a thing that I got to make winter more tolerable for me here in Chicago, and I think it was, like, a heated blanket [laughs]. And I am similarly in that space this year of like, what can I do or get to make this winter better than last winter? So, this year, what I got that I'm really excited to use— it actually just came in the mail—is this ceramic pot called the donabe that's kind of mainly used for Japanese cooking, especially, like, hot pot. And so, it will be a huge improvement to my soup game this year [laughs]. Similarly, it's kind of, like, one of those small things where you can take it from the stovetop where you're cooking straight to the table, and I'm so looking forward to that. It's kind of like your hot beverage in your hand but, like, three times the size [laughs]. JOËL: Right. The family-style version of it. STEPHANIE: Yeah, exactly. So, that's what I'm really looking forward to this year as something that is just, like, I don't know, a little small upgrade to my regular soup routine. But I think I will get a lot of pleasure [laughs] out of it. JOËL: What do you normally cook in that style of pot? Is it typically you do a hot pot in there, or is it meant for soups? STEPHANIE: Yeah, it holds heat really well, so I think that's why it's used for soup a lot. And the one that I got specifically has a little ceramic steamer plate as well. And so, I'm looking forward to having, like, this setup that's made for steaming, where you don't have to have any, like, too many extra bits. And, again, it can go from stove to table, and that's one less thing I [chuckles] need to wash. JOËL: I love it. So, something else that is kind of new in your world is you'd mentioned on a recent episode you'd wrapped up with your current client. And you've rotated on to not exactly a new client but a new almost line of business. You're doing a rotation with our support and maintenance team. Can you tell us a little bit about what that is like? STEPHANIE: Yeah. I'm excited to share more about it because this is my first time on this team doing this work. And it's pretty new for thoughtbot, too. I think it's only, like, a year old that we have had this sub-team of the one that you and I are on, Boost. In the sub-team, support and maintenance is focused on providing flexible part-time work for clients who are just needing some dedicated hours, not necessarily for, you know, a lot of, like, intense new feature work, but making sure that things are running smoothly. A lot of the clients, you know, have had Rails apps that are several years old, that are chugging along [chuckles], just need that, like, attention every now and then to make sure that upgrades are happening, fix any bugs, kind of as the app just continues to work and provide value. And then, occasionally, there is a little bit of feature work. But the interesting thing about being on this team is that instead of being on one client full-time, you are working on a lot of different clients at the same time, and a lot of them are on retainers. So, they maybe have, like, 20 hours a month of work that gets filled with kind of whatever tasks need to be done during that time. So yeah, I recently joined a few days ago and have been very surprised by kind of this style of work. It's different from what I'm used to. JOËL: That seems pretty different than the sort of traditional thoughtbot client engagement. Typically, if I'm a client and I'm hiring a team from thoughtbot, as a client, I get sort of a dedicated team. And they're probably either building some things for me or maybe working with my team and sort of full-time building features. Whereas if I hire the support and maintenance team, it sounds like it's a bit more ad hoc. And it's things I assume it's like, oh, we probably need to upgrade our Rails version since a new release came out last month. Can you do that? Here's a small bug that was reported. Can somebody fix that? Things along those lines. Is that pretty approximate of what the experience is for a client? STEPHANIE: Yeah, I would say so. I think the other surprising thing has been there have been a little bit of more DevOps type of tasks as well mixed in there. Because oftentimes, these are smaller clients who maybe have, like, a few developers actively working on new features and that type of stuff. But there is, like, so much of the connecting work that needs to happen when you have an application. And if you don't have a full in-house team for that, that often gets put on developers' plates. But it's kind of nice to have this flexible support and maintenance team, again, to, like, do the work as it comes up. A lot of it is not necessarily, like, stuff that can be planned in advance. It's kind of like, oh, we're hitting, like, our usage limit for this Heroku add-on. Let's evaluate if this is still working for us, if this is a good tier to be on. Like, should we upgrade? Are there other levers we could pull or adjustments we can make? So, that's actually been some of the stuff that I've been working on, too, which is, again, a little bit different from normal development work but also still very much related. And it's all kind of part of the job. And, you know, a lot of the skills are transferable. And to know how to do development in a framework then sets you up, I think, really well to, like, be able to make those kinds of evaluations. JOËL: So, it sounds like you almost, in a sense, provide a bit of a velocity cushion for clients so that if something does come up where they would maybe normally need to pull a dev off of feature work to do some side thing for a couple of days, you can come in and handle that so that their dev team stays focused on shipping features. STEPHANIE: Yeah, I like that phrase you used: velocity cushion. That's cool. I like it. The other surprising thing that I have kind of quite enjoyed, at least for now, is because we bill a little bit differently on this work; we have to track our hours more explicitly. And that has actually helped me focus a lot more on what I'm doing and if I should continue to be doing what I'm doing. I'm timeboxing things a lot more because I know that if there is a ceiling on the number of hours, I want to make sure that that time is spent in the most valuable way. And I also really enjoy, like, the boundaries of timeboxing, yes, but also, like, the tasks are usually scoped pretty narrowly so that they are things that you can accomplish, definitely in the week, because you don't know if you'll kind of still be working for this client next week but even more so, like, within a few days. And that is nice because I can kind of, like, you know, track my hours, finish the task, and then feel a little bit more free to go do something else without being, like, okay, like, what's the next thing that I need to be doing? There's a little bit more freedom, I think, when you're kind of, like, optimizing towards, like, finishing each item. JOËL: Do the stories of the work that you have to do does it typically come kind of pre-scoped? Are you involved in making sure that it has, like, very aggressive scoping? STEPHANIE: Yeah. So far, I've not been involved in doing the scoping work, and it has come pre-scoped, which has been nice. This was also, again, just different. Because I was on a client team previously, a lot of the work to be done was the disambiguating, the, like, figuring out what to be doing. Whereas here, because, again, we're kind of optimized for people coming in and out, if there is uncertainty or lack of clarity, it's pointed out early, and someone is like, "Okay, I will take care of this. Like, I'll take the lead on this so that it can be handed off." One client that I'm working on is using Basecamp's Shape Up methodology, which I actually hadn't worked with in a very explicit way before. And that has been interesting to learn about a little bit, too. One thing that I have enjoyed about it is instead of sprints, they're called cycles. And I like that a lot because, you know, sprints kind of have the connotation of, like, you're running as fast as you can but also, like, you can't run that way forever [laughs]. And so, even that, like, little bit of rewording change is really nice. The variable part is scope, right? It's we're focused on delivering something completely and very intentionally cutting scope as kind of the main lever. JOËL: How do you maintain sort of focus and flow if you're jumping across multiple clients? Because you said, you work with multiple clients as part of this team. And I feel like I can get a little bit frustrated sometimes, even just jumping between, like, tickets within one project. And so, I could imagine that jumping between different clients during the week or even the day might be really disruptive. Have you found techniques to help you stay in the flow? STEPHANIE: Yeah, that is a tough one because, also, every client has their different application; you then have to start up on [laughs] your local machine, and that is kind of annoying. You know, I do still tend to kind of, like, bundle similar work together. If, like, there's a few things I can do for a client on one day, I'll make sure to focus on that. But what I mentioned earlier about, like, seeing something to completion has been really, I want to say, fun even. Because it then kind of, like, frees up that mental space of, like, okay, I don't have to, like, have this thing that I'm working on lingering in my head about, like, oh, did I forget to do something? Or, you know, have, like, shower thoughts of like, oh, I just thought of a new way to implement this [laughs] feature because it doesn't spill over as much as maybe larger initiatives anyway. And so, I am context-switching, but it's only kind of after I've gotten something to a good place where I've left all of the notes. And that's another thing that I'm now kind of compelled to do a little more actively. It's like, every single day, I'm kind of making sure that the work that I've done has been reported on, one, because I have to track my hours, so, you know, and I sometimes leave notes about what that time was spent on doing. And also, when the expectation is that someone else will be picking up, then there's no, like, oh, like, let me hold on to this, and only when I know that I have to hand off something that's when I'll do the, like, dedicated knowledge dumping. It's kind of just built into the process a little more frequently. JOËL: So, you're setting up for, like, an imminent vacation factor. STEPHANIE: Yeah. Which I kind of like because then I can take a vacation [laughs] whenever I want and not have to worry too much about, oh, did I do everything I needed to do before I leave? JOËL: So, you know, these practices that you're doing are specifically adapted for the style of work that you have. Are there any that you think you would bring to your own practice if you ever rotated back on to a dedicated client project, anything that you would do there that you would want to include from your practice here? STEPHANIE: Yeah. It does sound kind of weird because part of what's nice about being on a full-time team is that there is less, oh, if I don't get something done today, I have tomorrow to do it [laughs]. And it seems like that would be like, oh, like, kind of take the pressure off a little bit. But I would be really curious to continue having, like, such an intense awareness about how I'm spending my time. Because I've certainly gotten a little bit lax on, like, full-time development work when you just go down a rabbit hole [laughs] and you come out, like, three hours later, and you're like, "What did I just do?" [laughs] And, you know, maybe that's what needed to be done, and that's fine. But if you have the information that it took you three hours, you can at least make a better-informed decision about, like, oh, maybe I should have stopped a little earlier or, like, yeah, it took about three hours, and that's okay. I think that would be an interesting area to incorporate and to be able to report more frequently. And I also like to know how other people spend their time, too. So, just, like, that sharing of information would also be really beneficial even to, like, a team. JOËL: What about the more aggressive documentation? Is that something that...because that can be really time-consuming, I imagine, as well. Is that something that you would value in a kind of, more focused full-time project context? STEPHANIE: Yeah. One part I've enjoyed about it is that I'm documenting, like, decision-making a lot more actively where, you know, I'm kind of, like, surfacing to be like, hey, here's the outcomes of, like, my research. We're not as, you know, embedded in the business, and we don't have as much of that, like, context and knowledge about what the best solutions are all the time. I'm documenting all of that, you know, usually, for the client stakeholder to be like, "Hey, here's my recommendations, like, how do you want to...what do you think is the best way to go? On one hand, it's kind of nice not to have to, like, be solely responsible for making that decision, right? And I'm kind of, like, leaning on, like, hey, like, you're the expert of your application and your product, you know, here's what I've learned. And now I've, like, put this all, like, for you and presented it to you. And I think that, for me, has gotten lost sometimes when I end up being the same person of, like, doing the research and then deciding, and it just kind of ends up being held in my head. And that, I think, is something really important to document, even if it's just for other people to, like, see how that process might work or, like, what things I already considered or didn't try. That exercise, I think, can be really important. So, so far, the documentation has not necessarily been, like, code level, but more, like, for each task, it's, like, showing your work, right? And not in a, like, you're being monitored [laughs] sort of way but in a way that supports it getting done with a lot of that turnover. JOËL: It's almost like a mini report that you're doing. So, you'd mentioned, for example, an application running into memory problems on Heroku. It sounds like you would then go maybe investigate that and then make some recommendations on whether they need to increase some dynos or maybe make some internal changes. It sounds like you may or may not be the one to execute those changes. But you would write up some, like, a mini report and submit that to the client, and then they can make their own execution choices. STEPHANIE: Yeah, exactly. And they can execute it themselves or then create a new ticket for the next person rotating on to support and maintenance to tackle it in a different cycle. JOËL: So, support and maintenance doesn't just do the investigation. Your team might do the execution as well. It's just that the sort of more research-y stuff and the execution stuff gets split out into different tickets because it's so tightly scoped. STEPHANIE: Yeah, that sounds right. JOËL: I like that. STEPHANIE: One area that I wasn't sure that I was going to like so much about this kind of work is, you know, when you're not kind of embedded on a team, I was thinking that I might not feel as connected, or I would miss a bit of that getting to know people and just, like, seeing people face to face on a daily basis. I'm still evaluating how that would go so far because it has definitely been, like, mostly asynchronous communication, you know, which is what works well for this type of the style of team or project. But I think what has been helpful is realizing that, like, oh yeah, like, I can also get that elsewhere, you know, with thoughtbot folks like with you doing this podcast every week. And right now, there are, like, two Boost members who are doing support and maintenance full time, and folks who are unbooked kind of come in and out. And I can see that there's still a team. So, it's not nearly as kind of, like, isolating as what I had thought it would be. JOËL: There's something that's really curious to me, I think, sitting at the intersection of the idea of fostering more team interactions and the sort of, like, mini reports that you write. And that's that I would love to see more sharing among all of us at thoughtbot about different interesting problems that we've had to solve or that we're tackling on different client work. Because I think in that case, it's a situation where we all just learn something, you know, maybe I've never had to deal with a memory leak or might not even have an idea of, like, how to approach memory issues on Heroku. So, seeing your little mini report, if you'd maybe share that, and, you know, maybe it can be anonymized in some way if needs to, I think would be really nice, at the very least, something that could be done, like, internally. So, I almost wonder if, like, building that practice of, you know, maybe not for every ticket that I do because, you know, I don't want to just be dumping my tickets in the thoughtbot Slack. But I run into something interesting and be like, oh, let me tell a little story about this and do a little write-up. That might be something that's good for the whole team and not just for folks who are on support and maintenance. STEPHANIE: Yeah, absolutely. As you were saying that, I was thinking about how it does kind of encourage me to find support outside of my, like, immediate team, right? Because I don't necessarily have one with the client and to, I don't know, I'm imagining, like, these roots growing in terms of different communities I'm a part of and bringing those problems just outside of my internal world, and kind of getting that outside feedback because by necessity a little bit, right? But also, with the added benefit of, you know, I think that's also how a lot of people end up writing content that gets shared with the world. So, I had the misconception that I would be kind of just, like, on my own off doing things like just tickets and being a little coding robot, but I've been surprised by it feels very fresh and new. So, I think, I guess, I was needing a little bit of that [laughs]. JOËL: I was having a conversation with another thoughtboter recently about how valuable sometimes change can be for its own sake and how that can sort of refresh. You want it just at the rate where you have a chance to build some stability. You don't want chaos. But sometimes change can sort of take you out of a rut, give you energy, maybe sort of restart some good habits that you had sort of let atrophy. And that finding, like, just that right level of shaking things up can really help a team, you know, get their effectiveness to the next level. STEPHANIE: Yeah. I like what you said about good habits, for sure. A couple of other random, little things that I just thought of about what I've liked is, I don't know, maybe this is a little silly. But we, you know, use shared credentials for logging into different services and applications or third parties that clients are using. And that has actually been something that has been so easy [laughs] and very low friction compared to, you know, joining a new project and manually be added as, like, your individual account to all of the different things. And things inevitably get forgotten, and then you have to rely on someone else to do it. And sometimes they don't get back to you [laughs] for a while. The self-serviceness of this work has been cool, too. And I just, yeah, wanted to say that I really appreciated the thought that went into making it as easy as possible to be like, yeah, I can find the credentials here. It is, you know, a bit more anonymized because I'm just using, like, a shared account. JOËL: Like a generic thoughtbot account on a client system rather than stephanie@thoughtbot. STEPHANIE: Yeah, exactly. But I think I saved so much time [laughs] this week just being able to do all of that myself and, you know, knowing where to look first before having to ask. JOËL: I guess you'd need something like that, right? If you're only jumping in on a project for the first time, for a couple of hours or something like that, you don't want to go through a whole onboarding process because that might then, like, easily double. You know, instead of doing two hours on this project, you're now doing four. STEPHANIE: Yeah, exactly. I guess the other takeaway, for me, was like, oh, definitely, if I were to have to set up accounts [laughs] for an application, you know, I've obviously seen where it was like, very clearly, like, the founder having created all these personal accounts for this services, and people are still using their credentials many years later [laughs], even though they probably, like, maybe may not even work for the company anymore. But yeah, the shared credentials and using that generic account that anyone can kind of get into when needed has really lowered the barrier to jump into doing that work, right? And especially because, like you said, it reduces that time. And we're, you know, billing by the hour anyway. So, it's kind of a win-win situation. JOËL: And I totally understand why you would not want something like that for a longer engagement. But for something like support and maintenance, it sounds like it was the right choice. STEPHANIE: Yeah, yeah. Again, I just mentioned it because it's just different. And so, maybe if this sparks any ideas for our listeners about how processes could be different or, like, the styles or ways of working can be different, I think that would be cool. JOËL: And just to be clear here, it sounds like what you're doing is for sort of each client; you create a separate set of credentials that are for that client but that are about thoughtbot generically. You don't have, like, one thoughtbot email and password that we reuse for every client. STEPHANIE: [laughs] Oh yes. That would be not so good [laughs] if we got hacked and suddenly, now they have access to everything. JOËL: So, every client gets its own unique email password combo. We're using security best practices here. And then, since you do have to share them through a team, are you doing some sort of, like, shared 1Password vault or something along those lines? STEPHANIE: Yeah, we are using a shared 1Password vault. That is definitely what I meant [laughs] the first time when I was mentioning the shared credentials, where that was basically the only thing I had to get onboarded to, the vault, for support and maintenance to be able to hit the ground running. JOËL: So, this sounds like a pretty exciting new style of project for you. Is this something that you would see yourself preferring to do longer term, to sort of focus on this style of project? Or do you think that you'd like to come back to more classic project work in the near future? STEPHANIE: I'm not sure yet, but I'm also hoping to have an answer to that question. And it definitely does feel like an experiment for me personally. I can see liking it, and that also fitting well with some of my longer-term goals of being able to, like, step back from work. Maybe working fewer days a week is something that I've, like, thought about in terms of, like, a long-term goal of mine because I'm not as needed [laughs] on a team. Which I think, in the past, I also had a bit of a misconception that, like, in order to be a good developer, I had to have all the domain knowledge, and be indispensable, and, like, be the go-to person to answer all the questions. But now I'm at a point where I don't want to [laughs] necessarily have to answer, like, every question because that creates, like, a dependency on me. And if I need to step away from work, then that could be tough, right? The vacation factor that you mentioned. So, this style of work is very interesting in terms of if it might provide me a little bit more of that, not exactly work-life balance, but just kind of be closer to my goals in terms of what I want out of work and my time. And, hopefully, I'm going to be doing this next week, but I don't know because that's the nature of it [laughs]. But if I am, then I'll definitely have more to say about it. Probably. JOËL: Well, it definitely sounds like we'll have to check in again on what's, I guess, not so new in your world on a future episode. On that note, shall we wrap up? STEPHANIE: Let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at: tbot.io/referral. Or you can email us at referrals@thoughtbot.com with any questions.
Joël recaps his time at RubyConf! He shares insights from his talk about different aspects of time in software development, emphasizing the interaction with the audience and the importance of post-talk discussions. Stephanie talks about wrapping up a long-term client project, the benefits of change and variety in consulting, and maintaining a balance between project engagement and avoiding burnout. They also discuss strategies for maintaining work-life balance, such as physical separation and device management, particularly in a remote work environment. Rubyconf (https://rubyconf.org/) Joël's talk slides (https://speakerdeck.com/joelq/which-time-is-it) Flaky test summary slide (https://speakerdeck.com/aridlehoover/the-secret-ingredient-how-to-understand-and-resolve-just-about-any-flaky-test?slide=170) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: Well, as of this recording, I have just gotten back from spending the week in San Diego for RubyConf. STEPHANIE: Yay, so fun. JOËL: It's always so much fun to connect with the community over there, talk to other people from different companies who work in Ruby, to be inspired by the talks. This year, I was speaking, so I gave a talk on time and how it's not a single thing but multiple different quantities. In particular, I distinguish between a moment in time like a point, a duration and amount of time, and then a time of day, which is time unconnected to a particular day, and how those all connect together in the software that we write. STEPHANIE: Awesome. How did it go? How was it received? JOËL: It was very well received. I got a lot of people come up to me afterwards and make a variety of time puns, which those are so easy to make. I had to hold myself back not to put too many in the talk itself. I think I kept it pretty clean. There were definitely a couple of time puns in the description of the talk, though. STEPHANIE: Yeah, absolutely. You have to keep some in there. But I hear you that you don't want it to become too punny [laughs]. What I really love about conferences, and we've talked a little bit about this before, is the, you know, like, engagement and being able to connect with people. And you give a talk, but then that ends up leading to a lot of, like, discussions about it and related topics afterwards in the hallway or sitting together over a meal. JOËL: I like to, in my talks, give little kind of hooks for people who want to have those conversations in the hallway. You know, sometimes it's intimidating to just go up to a speaker and be like, oh, I want to, like, dig into their talk a little bit. But I don't have anything to say other than just, like, "I liked your talk." So, if there's any sort of side trails I had to cut for the talk, I might give a shout-out to it and say, "Hey, if you want to learn more about this aspect, come talk to me afterwards." So, one thing that I put in this particular talk was like, "Hey, we're looking at these different graphical ways to think about time. These are similar to but not the same as thinking of time as a one-dimensional vector and applying vector math to it, which is a whole other side topic. If you want to nerd out about that, come find me in the hallway afterwards, and I'd love to go deeper on it." And yeah, some people did. STEPHANIE: That's really smart. I like that a lot. You're inviting more conversation about it, which I know, like, you also really enjoy just, like, taking it further or, like, caring about other people's experiences or their thoughts about vector math [laughs]. JOËL: I think it serves two purposes, right? It allows people to connect with me as a speaker. And it also allows me to feel better about pruning certain parts of my talk and saying, look, this didn't make sense to keep in the talk, but it's cool material. I'd love to have a continuing conversation about this. So, here's a path we could have taken. I'm choosing not to, as a speaker, but if you want to take that branch with me, let's have that afterwards in the hallway. STEPHANIE: Yeah. Or even as, like, new content for yourself or for someone else to take with them if they want to explore that further because, you know, there's always something more to explore [chuckles]. JOËL: I've absolutely done that with past talks. I've taken a thing I had to prune and turned it into a blog post. A recent example of that was when I gave a talk at RailsConf Portland, which I guess is not so recent. I was talking about ways to deal with a test suite that's making too many database requests. And talking about how sometimes misusing let in your RSpec tests can lead to more database requests than you expect. And I had a whole section about how to better understand what database requests will actually be made by a series of let expressions and dealing with the eager versus lazy and all of that. I had to cut it. But I was then able to make a blog post about it and then talk about this really cool technique involving dependency graphs. And that was really fun. So, that was a thing where I was able to say, look, here's some content that didn't make it into the talk because I needed to focus on other things. But as its own little, like, side piece of content, it absolutely works, and here's a blog post. STEPHANIE: Yeah. And then I think it turned into a Bike Shed episode, too [laughs]. JOËL: I think it did, yes. I think, in many ways, creativity begets creativity. It's hard to get started writing or producing content or whatever, but once you do, every idea you have kind of spawns new ideas. And then, pretty soon, you have a backlog that you can't go through. STEPHANIE: That's awesome. Any other highlights from the conference you want to shout out? JOËL: I'd love to give a shout-out to a couple of talks that I went to, Aji Slater's talk on the Enigma machine as a German code machine from World War II and how we can sort of implement our own in Ruby and an exploration of object-oriented programming was fantastic. Aji is just a masterful storyteller. So, that was really great. And then Alan Ridlehoover's talk on dealing with flaky tests that one, I think, was particularly useful because I think it's one of the talks that is going to be immediately relevant on Monday morning for, like, every developer that was in that room and is going back to their regular day job. And they can immediately use all of those principles that Alan talked about to deal with the flaky tests in their test suite. And there's, in particular, at the end of his presentation, Alan has this summary slide. He kind of broke down flakiness across three different categories and then talked about different strategies for identifying and then fixing tests that were flaky because of those reasons. And he has this table where he sort of summarizes basically the entire talk. And I feel like that's the kind of thing that I'm going to save as a cheat sheet. And that can be, like, I'm going to link to this and share it all over because it's really useful. Alan has already put his slides up online. It's all linked to that particular slide in the show notes because I think that all of you would benefit from seeing that. The talks themselves are recorded, but they're not going to be out for a couple of weeks. I'm sure when they do, we're going to go through and watch some and probably comment on some of the talks as well. So, Stephanie, what is new in your world? STEPHANIE: Yeah. So, I'm celebrating wrapping up a client project after a nine-month engagement. JOËL: Whoa, that's a pretty long project. STEPHANIE: Yeah, that's definitely on the longer side for thoughtbot. And I'm, I don't know, just, like, feeling really excited for a change, feeling really, you know, proud of kind of, like, all of the work that we had done. You know, we had been working with this client for a long time and had been, you know, continuing to deliver value to them to want to keep working with us for that long. But I'm, yeah, just looking forward to a refresh. And I think that's one of my favorite things about consulting is that, you know, you can inject something new into your work life at a kind of regular cadence. And, at least for me, that's really important in reducing or, like, preventing the burnout. So, this time around, I kind of started to notice, and other people, too, like my manager, that I was maybe losing a bit of steam on this client project because I had been working on it for so long. And part of, you know, what success at thoughtbot means is that, like, we as employees are also feeling fulfilled, right? And, you know, what are the different ways that we can try to make sure that that remains the case? And kind of rotating folks on different projects and kind of making sure that things do feel fresh and exciting is really important. And so, I feel very grateful that other people were able to point that out for me, too, when I wasn't even fully realizing it. You know, I had people checking in on me and being like, "Hey, like, you've been on this for a while now. Kind of what I've been hearing is that, like, maybe you do need something new." I'm just excited to get that change. JOËL: How do you find the balance between sort of feeling fulfilled and maybe, you know, finding that point where maybe you're feeling you're running out of steam–versus, you know, some projects are really complex, take a while to ramp up; you want to feel productive; you want to feel like you have contributed in a significant way to a project? How do you navigate that balance? STEPHANIE: Yeah. So, the flip side is, like, I also don't think I would enjoy having to be changing projects all the time like every couple of months. That maybe is a little too much for me because I do like to...on our team, Boost, we embed on our team. We get to know our teammates. We are, like, building relationships with them, and supporting them, and teaching them. And all of that is really also fulfilling for me, but you can't really do that as much if you're on more shorter-term engagements. And then all of that, like, becomes worthwhile once you're kind of in that, like, maybe four or five six month period where you're like, you've finally gotten your groove. And you're like, I'm contributing. I know how this team works. I can start to see patterns or, like, maybe opportunities or gaps. And that is all really cool, and I think also another part of what I really like about being on Boost. But yeah, I think what I...that losing steam feeling, I started to identify, like, I didn't have as much energy or excitement to push forward change. When you kind of get a little bit too comfortable or start to get that feeling of, well, these things are the way they are [laughs], -- JOËL: Right. Right. STEPHANIE: I've now identified that that is kind of, like, a signal, right? JOËL: Maybe time for a new project. STEPHANIE: Right. Like starting to feel a little bit less motivated or, like, less excited to push myself and push the team a little bit in areas that it needs to be pushed. And so, that might be a good time for someone else at thoughtbot to, like, rotate in or maybe kind of close the chapter on what we've been able to do for a client. JOËL: It's hard to be at 100% all the time and sort of always have that motivation to push things to the max, and yeah, variety definitely helps with that. How do you feel about finding signals that maybe you need a break, maybe not from the project but just in general? The idea of taking PTO or having kind of a rest day. STEPHANIE: Oh yeah. I, this year, have tried out taking time off but not going anywhere just, like, being at home but being on vacation. And that was really great because then it was kind of, like, less about, like, oh, I want to take this trip in this time of year to this place and more like, oh, I need some rest or, like, I just need a little break. And that can be at home, right? Maybe during the day, I'm able to do stuff that I keep putting off or trying out new things that I just can't seem to find the time to do [chuckles] during my normal work schedule. So, that has been fun. JOËL: I think, yeah, sometimes, for me, I will sort of hit that moment where I feel like I don't have the ability to give 100%. And sometimes that can be a signal to be like, hey, have you taken any time off recently? Maybe you should schedule something. Because being able to refresh, even short-term, can sort of give an extra boost of energy in a way where...maybe it's not time for a rotation yet, but just taking a little bit of a break in there can sort of, I guess, extend the time where I feel like I'm contributing at the level that I want to be. STEPHANIE: Yeah. And I actually want to point out that a lot of that can also be, like, investing in your life outside of work, too, so that you can come to work with a different approach. I've mentioned the month that I spent in the Hudson Valley in New York and, like, when I was there, I felt, like, so different. I was, you know, just, like, so much more excited about all the, like, novel things that I was experiencing that I could show up to work and be like, oh yeah, like, I'm feeling good today. So, I have all this, you know, energy to bring to the tasks that I have at work. And yeah, so even though it wasn't necessarily time off, it was investing in other things in my life that then brought that refresh at work, even though nothing at work really changed [laughs]. JOËL: I think there's something to be said for the sort of energy boost you get from novelty and change, and some of that you get it from maybe rotating to a different project. But like you were saying, you can change your environment, and that can happen as well. And, you know, sometimes it's going halfway across the country to live in a place for a month. I sometimes do that in a smaller way by saying, oh, I'm going to work this morning from a coffee shop or something like that. And just say, look, by changing the environment, I can maybe get some focus or some energy that I wouldn't have if I were just doing same old, same old. STEPHANIE: Yeah, that's a good point. So, one particularly surprising refresh that I experienced in offboarding from my client work is coming back to my thoughtbot, like, internal company laptop, which had been sitting gathering dust [laughs] a little bit because I had a client-issued laptop that I was working in most of the time. And yeah, I didn't realize how different it would feel. I had, you know, gotten everything set up on my, you know, my thoughtbot computer just the way that I liked it, stuff that I'd never kind of bothered to set up on my other client-issued laptop. And then I came back to it, and then it ended up being a little bit surprising. I was like, oh, the icons are smaller on this [laughs] computer than the other computer. But it definitely did feel like returning to home, I think, instead of, like, being a guest in someone else's house that you haven't quite, like, put all your clothes in the closet or in the drawers. You're still maybe, like, living out of a suitcase a little bit [laughs]. So yeah, I was kind of very excited to be in my own space on my computer again. JOËL: I love the metaphor of coming home, and yeah, being in your own space, sleeping in your own bed. There's definitely some of that that I feel, I think, when I come back to my thoughtbot laptop as well. Do you feel like you get a different sense of connection with the rest of our thoughtbot colleagues when you're working on the thoughtbot-issued laptop versus a client-issued one? STEPHANIE: Yeah. Even though on my client-issued computer I had the thoughtbot Slack, like, open on there so I could be checking in, I wasn't necessarily in, like, other thoughtbot digital spaces as much, right? So, our, like, project management tools and our, like, internal company web app, those were things that I was on less of naturally because, like, the majority of my work was client work, and I was all in their digital spaces. But coming back and checking in on, like, all the GitHub discussions that have been happening while I haven't had enough time to catch up on them, just realizing that things were happening [laughs] even when I was doing something else, that is both cool and also like, oh wow, like, kind of sad that I [chuckles] missed out on some of this as it was going on. JOËL: That's pretty similar to my experience. For me, it almost feels a little bit like the difference between back when we used to be in person because thoughtbot is now fully remote. I would go, usually, depending on the client, maybe a couple of days a week working from their offices if they had an office. Versus some clients, they would come to our office, and we would work all week out of the thoughtbot offices, particularly if it was like a startup founder or something, and they might not already have office space. And that difference and feeling the connection that I would have from the rest of the thoughtbot team if I were, let's say, four days a week out of a client office versus two or four days a week out of the thoughtbot office feels kind of similar to what it's like working on a client-issued laptop versus on a thoughtbot-issued one. STEPHANIE: Another thing that I guess I forgot about or, like, wasn't expecting to do was all the cleanup, just the updating of things on my laptop as I kind of had it been sitting. And it reminded me to, I guess, extend that, like, coming home metaphor a little bit more. In the game Animal Crossing, if you haven't played the game in a while because it tracks, like, real-time, so it knows if you haven't, you know, played the game in a few months, when you wake up in your home, there's a bunch of cockroaches running around [laughs], and you have to go and chase and, like, squash them to clean it up. JOËL: Oh no. STEPHANIE: And it kind of felt like that opening my computer. I was like, oh, like, my, like, you know, OS is out of date. My browsers are out of date. I decided to get an internal company project running in my local development again, and I had to update so many things, you know, like, install the new Ruby version that the app had, you know, been upgraded to and upgrade, like, OpenSSL and all of that stuff on my machine to, yeah, get the app running again. And like I mentioned earlier, just the idea of like, oh yeah, this has evolved and changed, like, without me [laughs] was just, you know, interesting to see. And catching myself up to speed on that was not trivial work. So yeah, like, all that maintenance stuff still got to do it. It's, like, the digital cleanup, right? JOËL: Exactly. So, you mentioned that on the client machine, you still had the thoughtbot Slack. So, you were able to keep up at least some messages there on one device. I'm curious about the experience, maybe going the other way. How much does thoughtbot stuff bleed into your personal devices, if at all? STEPHANIE: Barely. I am very strict about that, I think. I used to have Slack on my phone, I don't know, just, like, in an earlier time in my career. But now I have it a rule to keep it off. I think the only thing that I have is my calendar, so no email either. Like, that is something that I, like, don't like to check on my personal time. Yeah, so it really just is calendar just in case I'm, like, out in the morning and need to be, like, oh, when is my first meeting? But [laughs] I will say that the one kind of silly thing is that I also refuse to sign into my Google account for work. So, I just have the calendar, like, added to my personal calendar but all the events are private. So, I can't actually see what the events are [laughs]. I just know that I have something going on at, like, 10:00 a.m. So, I got to make sure I'm back home by then [laughs], which is not so ideal. But at the risk of being signed in and having other things bleed into my personal devices, I'm just living with that for now [laughs]. JOËL: What I'm hearing is that I could put some mystery events on your calendar, and you would have a fun surprise in the morning because you wouldn't know what it is. STEPHANIE: Yeah, that is true [laughs]. If you put, like, a meeting at, like, 8:00 a.m., [laughs] then I'm like, oh no, what's this? And then I arrive, and it's just, like [laughs], a fun prank meeting. So, you know, you were talking about how you were at the conference this week. And I'm wondering, how connected were you to work life? JOËL: Uh, not very. I tried to be very present in the moment at the conference. So, I'm, you know, connected to all the other thoughtboters who were there and connecting with the attendees. I do have Slack on my phone, so if I do need to check it for something. There was a little bit of communication that was going on for different things regarding the conference, so I did check in for that. But otherwise, I tried to really stay focused on the in-person things that are happening. I'm not doing any client work during those days that I'm at RubyConf, and so I don't need to deal with anything there. I had my thoughtbot laptop with me because that's what I used to give my presentation. But once the presentation was done, I closed that laptop and didn't open it again, and, honestly, that felt kind of good. STEPHANIE: Yeah, that is really nice. I'm the same way, where I try to be pretty connected at conferences, and, like, I will actually redownload Slack sometimes just for, like, coordinating purposes with other folks who are there. But I think I make it pretty clear that I'm, like, away. You know, like, I'm not actually...like, even though I'm on work time, I'm not doing any other work besides just being present there. JOËL: So, you mentioned the idea of work time. Do you have, like, a pretty strict boundary between personal time and work time and, like, try not to allow either to bleed into each other? STEPHANIE: Yeah. I can't remember if I've mentioned this on the show. I think I have, but I'm going to again because one of my favorite things that I picked up from The Bike Shed back when Chris Toomey and Steph Viccari were hosting the show is Chris had, like, a little ritual that he would do every day to signal that he was done with work. He would close his laptop and say, "Schedule shutdown complete," I think. And I've started adopting it because then it helps me be like, I'm not going to reopen my laptop after this because I have said the words. And even if I think of something that I maybe need to add to my to-do list, I will, instead of opening my computer and adding to my, like, whatever digital to-do list, I will, like, write it down on a piece of paper instead for the sake of, you know, not risking getting sucked back into, you know, whatever might be going on after the time that I've, like, decided that I need to be done. JOËL: So, you have a very strict divisioning between work time and personal time. STEPHANIE: Yeah, I would say so. I think it's important for me because even when I take time off, you know, sometimes folks might work a half day or something, right? I really struggle with having even a half day feel like, once I'm done with work, having that feel like okay, like, now I'm back in my personal time. I'd much prefer not working the entire day at all because that is kind of the only way that I can feel like I've totally reclaimed that time. Otherwise, it's like, once I start thinking about work stuff, it's like I need a mental boundary, right? Because if I'm thinking about a work problem, or, like, an interaction or, like, just anything, it's frustrating because it doesn't feel like time in my own brain [laughs] is my own. What do work and personal time boundaries look like for you? JOËL: I think it's evolved over time. Device usage is definitely a little bit more blurry for me. One thing that I have started doing since we've gone fully remote as the pandemic has been winding down and, you know, you can do things, but we're still working from home, is that more days than not, I work from home during the day, and then I leave my home during the evening. I do a variety of social activities. And because I like to be sort of present in the moment, that means that by being physically gone, I have totally disconnected because I'm not checking emails or anything like that. Even though I do have thoughtbot email on my phone, Gmail allows me to like log into my personal account and my thoughtbot account. I have to, like, switch between the two accounts, and so, that's, like, more work than I would want. I don't have any notifications come in for the thoughtbot account. So, unless I'm, like, really wanting to see if a particular email I'm waiting for has come in, I don't even look at it, ever. It's mostly just there in case I need to see something. And then, by being focused in the moment doing social things with other people, I don't find too much of a temptation to, like, let work life bleed into personal life. So, there's a bit of a physical disconnect that ends up happening by moving out of the space I work in into leaving my home. STEPHANIE: Yeah. And I'm sure it's different for everyone. As you were saying that, I was reminded of a funny meme that I saw a long time ago. I don't think I could find it if I tried to search for it. But basically, it's this guy who is, you know, sitting on one side of the couch, clearly working. And he's kind of hunched over and, like, typing and looking very serious. And then he, like, closes his laptop, moves over, like, just slides to the other side of the couch, opens his laptop. And then you see him, like, lay back, like, legs up on the coffee table. And it's, like, work computer, personal computer, but it's the same computer [laughs]. It's just the, like, how you've decided like, oh, it's time for, you know, legs up, Netflix watching [laughs]. JOËL: Yeah. Yeah. I'm curious: do you use your thoughtbot computer for any personal things? Or is it just you shut that down; you do the closing ritual, and then you do things on a separate device? STEPHANIE: Yeah, I do things on a separate device. I think the only thing there might be some overlap for are, like, career-related extracurriculars or just, like, development stuff that I'm interested in doing, like, separate from what I am paid to do. But that, you know, kind of overlaps a little bit because of, like, the tools and the stuff I have installed on my computer. And, you know, with our investment time, too, that ends up having a bit of a crossover. JOËL: I think I'm similar in that I'll tend to do development things on my thoughtbot machine, even though they're not necessarily thoughtbot-related, although they could be things that might slot into something like investment time. STEPHANIE: Yeah, yeah. And it's because you have all your stuff set up for it. Like, you're not [laughs] trying to install the latest Ruby version on two different machines, probably [laughs]. JOËL: Yeah. Also, my personal device is a Windows machine. And I've not wanted to bother learning how to set that up or use the Windows Subsystem for Linux or any of those tools, which, you know, may be good professional learning activities. But that's not where I've decided to invest my time. STEPHANIE: That makes sense. I had an interesting conversation with someone else today, actually, about devices because I had mentioned that, you know, sometimes I still need to incorporate my personal devices into work stuff, especially, like, two-factor authentication. And specifically on my last client project...I have a very old iPhone [laughs]. I need to start out by saying it's an iPhone 8 that I've had for, like, six or seven years. And so, it's old. Like, one time I went to the Apple store, and I was like, "Oh, I'm looking for a screen protector for this." And they're like, "Oh, it's an iPhone 8. Yikes." [laughs] This was, you know, like, not too long ago [laughs]. And the multi-factor authentication policy for my client was that, you know, we had to use this specific app. And it also had, like, security checks. Like, there's a security policy that it needed to be updated to the latest iOS. So, even if I personally didn't want to update my iOS [laughs], I felt compelled to because, otherwise, I would be locked out of the things that I needed to do at work [laughs]. JOËL: Yeah, that can be a challenge sometimes when you're adding work things to personal devices, maybe not because it's convenient and you want to, but because you don't have a choice for things like two-factor auth. STEPHANIE: Yeah, yeah. And then the person I was talking to actually suggested something I hadn't even thought about, which is like, "Oh, you know, if you really can't make it work, then, like, consider having that company issue another device for you to do the things that they're, like, requiring of you." And I hadn't even thought of that, so... And I'm not quite at the point where I'm like, everything has to be, like, completely separate [laughs], including two-factor auth. But, I don't know, something to consider, like, maybe that might be a place I get to if I'm feeling like I really want to keep those boundaries strict. JOËL: And I think it's interesting because, you know, when you think of the kind of work that we do, it's like, oh, we work with computers, but there are so many subfields within it. And device management and, just maybe, corporate IT, in general, is a whole subfield that is separate and almost a little bit alien. Two, I feel like me, as a software developer, I'm just aware of a little bit...like, I've read a couple of articles around...and this was, you know, years ago when the trend was starting called Bring Your Own Device. So, people who want to say, "Hey, I want to use my phone. I want to have my work email on my phone." But then does that mean that potentially you're leaking company memos and things? So, how do you secure that kind of thing? And everything that IT had to think through in order to allow that, the pros and cons. So, I think we're just kind of, as users of that system, touching the surface of it. But there's a lot of thought and discussion that, as an industry, the kind of corporate IT folks have gone through to struggle with how to balance a lot of those things. STEPHANIE: Yeah, yeah. I bet there's a lot of complexity or nuance there. I mean, we're just talking about, like, ways that we do or don't mix work and personal life. And for that kind of work, you know, that's, like, the job is to think really thoroughly about how people use their devices and what should and shouldn't be permissible. The last thing that I wanted to kind of ask about in terms of device management or, like, work and personal intermixing is the idea of being on call and your device being a way for work to reach you and that being a requirement, right? I feel very lucky to obviously not really be in that position. As consultants, like, we're not usually so embedded into a team that we're then brought into, like, an on-call rotation, and I think that's good for me. Like, I don't think that that is something I'd be interested in doing anytime soon. Do you have any experience with that? JOËL: I have not been on a project where I've had to be on call, and I think that's generally true for most of us at thoughtbot who are doing software development. I know those who are doing more kind of platformy SRE-type things are on call. And, in fact, we have specifically hired people in different regions around the world so that we can provide 24-hour coverage for that kind of thing. STEPHANIE: Yeah. And I imagine kind of like what we're talking about with work device management looks even different for that kind of role, where maybe you do need a lot more access to things, like, wherever you might be. JOËL: And maybe the answer there is you get issued a work-specific device and a work phone or something like that, or an old-school work pager. STEPHANIE: [laughs] JOËL: PagerDuty is not just a metaphoric thing. Back in the day, they used actual pagers. STEPHANIE: Yeah, that would be very funny. JOËL: So yeah, I can't speak to it from personal experience, but I could imagine that maybe some of the dynamics there might be a little bit different. And, you know, for some people, maybe it's fine to just have an app on your phone that pings you when something happens, and you have to be on call. And you're able to be present while waiting, like, in case you get pinged, but also let it go while you're on call. I can imagine that's, like, a really weird kind of, like, shadow, like, working, not working experience that I can't really speak to because I have not been in that position. STEPHANIE: Yeah. As you were saying that, I also had the thought that, like, our ability to step away from work and our devices is also very much dependent on, like, a company culture and those types of factors, right? Where, you know, it is okay for me to not be able to look at that stuff and just come back to it Monday morning, and I am very grateful [laughs] for that. Because I recognize that, like, not everyone is in that position where there might be a lot more pressure or urgency to be on top of that. But right now, for this time in my life, like, that's kind of how I like to work. JOËL: I think it kind of sits at the intersection of a few different things, right? There's sort of where you are personally. It might be a combination, like, personality and maybe, like, mental health, things like that, how you respond to how sharp or blurry those lines between work and personal life can be. Like you said, it's also an element of company culture. If there's a company culture that's really pushing to get into your personal life, maybe you need firmer boundaries. And then, finally, what we spent most of this episode talking about: technical solutions, whether that's, like, physically separating everything such that there are two devices. And you close down your laptop, and you're done for the day. And whether or not you allow any apps on your personal phone to carry with you after you leave for the day. So, I think at the intersection of those three is sort of how you're going to experience that, and every person is going to be a little bit different. Because those three...I guess I'm thinking of a Venn diagram. Those three circles are going to be different for everyone. STEPHANIE: Yeah, that makes complete sense. JOËL: On that note, shall we wrap up? STEPHANIE: Let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeee!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at: tbot.io/referral. Or you can email us at: referrals@thoughtbot.com with any questions.
Stephanie interviews Edward Loveall, a former thoughtbotter, now software developer at Relevant Healthcare. Part of their discussion centers around Edward's blog post on the tech industry's over-reliance on GitHub. He argues for the importance of exploring alternatives to avoid dependency on a single platform and encourages readers to make informed technological choices. The conversation broadens to include how to form opinions on technology, the balance between personal preferences and team decisions, and the importance of empathy and nuance in professional interactions. Both Stephanie and Edward highlight the value of considering various perspectives and tools in software development, advocating for a flexible, open-minded approach to technology and problem-solving in the tech industry. Relevant (https://relevant.healthcare/) Let's make sure Github doesn't become the only option (https://blog.edwardloveall.com/lets-make-sure-github-doesnt-become-the-only-option) And not but (https://blog.edwardloveall.com/and-not-but) Empathy Online (https://thoughtbot.com/blog/empathy-online) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. And today, I'm joined by a very special guest, a friend of the pod and former thoughtboter, Edward Loveall. EDWARD: Hello, thanks for having me. STEPHANIE: Edward, would you share a little bit about yourself and what you're doing these days? EDWARD: Yes, I am a software developer at a company called Relevant Healthcare. We do a lot of things, but the maybe high-level summary is we take very complicated medical data and help federally-funded health centers actually understand that data and help their population's health, which is really fun and really great. STEPHANIE: Awesome. So, Edward, what is new in your world? EDWARD: Let's see, this weekend...I live in a dense city. I live in Cambridge, Massachusetts, and it's pretty dense there. And a lot of houses are very tightly packed. And delivery drivers struggle to find the numbers on the houses sometimes because A, they're old and B, there is many of them. And so, we put up house numbers because I live in, like, a three-story kind of building, but there are two different addresses in the same three stories, which is very weird. And so [laughs], delivery drivers are like, "Where is number 10 or 15?" or whatever. And so, there's two different numbers. And so, we finally put up numbers after living here for, like, four years [chuckles]. So, now, hopefully, delivery drivers in the holiday busy season will be able to find our house [laughs]. STEPHANIE: That's great. Yeah, I have kind of a similar problem where, a lot of the times, delivery folks will think that my house is the big building next door. And the worst is those at the building next door they drop off their packages inside the little, like, entryway that is locked for people who don't live there. And so, I will see my package in the window and, you know, it has my name on it. It has, like, my address on it. And [laughs] some strategies that I've used is leaving a note on the door [laughter] that is, like, "Please redeliver my package over there," and, like, I'll draw an arrow to the direction of my house. Or sometimes I've been that person to just, like, buzz random [laughter] units and just hope that they, like, let me in, and then I'll grab my package. And, you know, if I know the neighbors, I'll, like, try to apologize the next time I see them. But sometimes I'll just be like, I just need to get my package [laughs]. EDWARD: You're writing documentation for those people working out in the streets. STEPHANIE: Yeah. But I'm glad you got that sorted. EDWARD: Yeah. What about you? What's new in your world? STEPHANIE: Well, I wanted to talk a little bit about a thing that you and I have been doing lately that I have been enjoying a lot. First of all, are you familiar with the group chat trend these days? Do you know what I'm talking about? EDWARD: No. STEPHANIE: Okay. It's basically this idea that, like, everyone is just connecting with their friends via a group chat now as opposed to social media. But as a person who is not a big group chat person, I can't, like, keep up with [chuckles], like, chatting with multiple people [laughter] at once. I much prefer, like, one-on-one interaction. And, like, a month ago, I asked you if you would be willing to try having a shared note, like, a shared iOS note that we have for items that we want to discuss with each other but, you know, the next time we either talk on the phone or, I don't know, things that are, like, less urgent than a text message would communicate but, like, stuff that we don't want to forget. EDWARD: Yeah. You're, like, putting a little message in my inbox and vice versa. And yeah, we get to just kind of, whenever we want, respond to it, or think about it, or use it as a topic for a conversation later. STEPHANIE: Yeah. And I think it is kind of a playbook from, like, a one-on-one with a manager. I know that that's, like, a strategy that some folks use. But I think it works well in the context of our friendship because it's just gotten, like, richer over time. You know, maybe in the beginning, we're like, oh, like, I don't know, here are some random things that I've thought about. But now we're having, like, whole discussions in the note [laughter]. Like, we will respond to each other, like, with sub-bullets [laughs]. And then we end up not even needing to talk about it on the phone because we've already had a whole conversation about it in the note. EDWARD: Which is good because neither of us are particularly brief when talking on the phone. And [laughs] we only dedicate, like, half an hour every two weeks. It sort of helps clear the decks a little. STEPHANIE: Yeah, yeah. So, that's what I recommend. Try a shared note for [laughs] your next friendship hangout. EDWARD: Yeah, it's great. I heartily recommend it. STEPHANIE: So, one of the things that we end up talking about a lot is various things that we've been reading about tech on the web [laughs]. And we share with each other a lot of, like, blog posts, or articles, various links, and recently, something of yours kind of resurfaced. You wrote a blog post about GitHub a little while ago about how, you know, as an industry, we should make sure that GitHub doesn't become our only option. EDWARD: Yeah, this was a post I wrote, I think, back in May, or at least earlier this year, and it got a bunch of traction. And it's a somewhat, I would say, controversial article or take. GitHub just had their developer conference, and it resurfaced again. And I don't have a habit of writing particularly controversial articles, I don't think. Most of my writing history has been technical posts like tutorials. Like, I wrote a whole tutorial on how to write SQL, or I did write one about how to communicate online. But I wasn't, like, so much responding to, like, a particular person's communication or a company's communication. And this is the first big post I've written that has been a lot more very heavily opinionated, very, like, targeted at a particular thing or entity, I guess you'd say. It's been received well, I think, mostly, and I'm proud of it. But it's a different little world for me, and it's a little scary, honestly. STEPHANIE: Yeah, I hear that, having an opinion [laughs], a very strong and maybe, like, a less popular opinion, and publishing that for the world. Could you recap what the thesis of it is for our listeners? EDWARD: Yeah, and I think you did a great job of it, too. I see GitHub or really any singular piece of technology that we have in...I'll say our stack with air quotes, but it's, you know, all the tools that we use and all the things that we use. It's a risk if you only have one of those things, let's say GitHub. Like, if the only way you know how to contribute to a code repository with, you know, 17 people all committing to that repository, if the only way you know how to do that is a pull request and GitHub goes away, and you don't have pull requests anymore, how are you going to contribute to code? It's not that you couldn't figure it out, or there aren't multiple ways or even other pull request equivalents on other sites. But it is a risk to rely on one company to provide all of the things that you potentially need, or even many of the things that you potentially need, without any alternatives. So, I wanted to try to lay out A: those risks, and B: encourage people to try alternatives, to say that GitHub is not necessarily bad, although they may not actually fit what you need for various reasons, or someone else for various reasons. But you should have an alternative in your back pocket so that in case something changes, or you get locked out, or they go away, or they decide to cancel that feature, or any number of other scenarios, you have greatly diminished that risk. So, that's the main thrust of the post. STEPHANIE: Yeah, I really appreciated it because, you know, I think a lot of us probably take GitHub for granted [laughs]. And, you know, every new thing that they kind of add to the platform is like, oh, like, cool, like, I can now do this. In the post, you kind of lay out all of the different features that GitHub has rolled out over the last, you know, couple of years. And when you see it all like that, you know, like, in addition to being, like, a code repository, you now have, like, GitHub Actions for CI/CD, you know, you can deploy static pages with it. It now has, like, an in-browser editor, and then, you know, Copilot, which, like, the more things that they [laughs] roll out, the more it's becoming, like, the one-stop shop, right? That, like, do all of your work here. And I appreciated kind of, like, seeing that and being like, oh, like, is this what I want? EDWARD: Right. Yeah, exactly. Yeah. And you mentioned a bunch. There's also issues and discussions. You mentioned their in-browser editor. But so many people use VS Code, which, while it was technically made by Microsoft, it's based on Electron, which was developed at GitHub. And GitHub even, like, took away their other Electron-based editor, Atom. And then now officially recommends VS Code. And everything from deploying all the way down to, like, thinking about and prioritizing features and editing the code and all of that pretty much could happen on GitHub. I think maybe the only thing they don't currently do is host non-static sites, maybe [laughs]. That's maybe about it. And who knows? Maybe they're working on that; as far as I know, they are, so... STEPHANIE: Yeah, absolutely. You also mentioned one thing that I really liked about the content in the post was that you talked about alternatives to GitHub, even, like, alternatives to all of the different features that we mentioned. I guess I'm wondering, like, what were you hoping that a reader from your blog post, like, what they would get out of reading and, like, what they would take away from kind of sharing your opinion? EDWARD: I wanted to try to meet people where I think they might be because I think a lot of people do use GitHub, and they do take it for granted. And they do sort of see it as this thing that they must use, or they want to use even, and that's fine. That's not necessarily a bad thing. I want them to see those alternatives and have at least some idea that there is something else out there, that GitHub doesn't become just not only the default, but, like, the only thing. I mean, to just [chuckles] re-paraphrase the title of the post, I want to make sure GitHub does not become the only option, right? I want people to realize that there are other options out there and be encouraged to try them. And I have found, for me, at least, the better way to do that is not to only focus on, like, hey, don't use GitHub. Like, I hope people did not come away with only that message or even that message at all. But that it is more, hey, maybe try something else out and to encourage you to try something out. I'm going to A: share the risks with you and B: give you some actual things to try. So, I talk about the things I'm using and some other platforms and different paradigms to think about and use. So, I hope they take those. We'll see what happens in the next, you know, months or years. And I'll probably never know if it was actually just from me or from many other conversations, and thoughts, and articles, and all that kind of stuff. But that's what it takes, so... STEPHANIE: Yeah. I think the other fun thing about kind of the, like, meta-conversation we're having about having an opinion and, like, sharing it with the world is that you don't even really say like, "This is better than GitHub," or, like, kind of make a statement about, like, you shouldn't use...you don't even say, "You shouldn't use GitHub," right? The message is, like, here are some options: try it out, and, like, decide for yourself. EDWARD: Yeah, exactly. I want to empower people to do that. I don't think it would have been useful if I'd just go and say, "Hey, don't do this." It's very frustrating to me to see posts that are only negatives. And, honestly, I've probably written those posts, like, I'm not above them necessarily. But I have found that trying to help people do what you want them to do, as silly and maybe obvious as that sounds, is a more effective way to get them to do what you want them to do [laughs], as opposed to say, "Hey, stop doing the thing I don't want you to do," or attack their identity, or their job, or some other aspect of their life. Human behavior does not respond well to that generally, at least in my experience. Like, having your identity tied up in a tool or a platform is, unfortunately, pretty common in, like, a tech space. Like, oh, like, Ruby on Rails is the best piece of software or something like that. And it's like, well, you might like it, and that might be the best thing for you. And personally, I really like Ruby on Rails. I think it does a great job of what it does. But as an example, I would not use Ruby on Rails to maybe build an iOS app. I could; I think that's possible, but I don't think that's maybe the best tool for that job. And so, trying to, again, meet people where they are. STEPHANIE: I guess it kind of goes back to what you're saying. It's like, you want to help people do what they are trying to do. EDWARD: Yeah. Maybe there's a little paternalistic thinking, too, of, like, what's good for the industry, even if it feels bad for you right now. I don't love that sort of paternalistic thinking. But if it's a real risk, it seems worth at least addressing or pointing out and letting people make that decision for themselves. STEPHANIE: Yeah, absolutely. I am actually kind of curious about how do you, like, decide something for yourself? You know, like, how do you form your own opinion about technology? I think, yeah, like, a lot of people take GitHub for granted. They use it because that's just what's used, and that may or may not be a good reason for doing so. But that was a position I was in for a long time, right? You know, especially when you're newer to the industry, you're like, oh, well, this is what the company uses, or this is what, like, the industry uses. But, like, how do you start to figure out for yourself, like, do I actually like this? Does this help me meet my goals and needs? Is it doing what I want it to be doing? Do you have any thoughts about that? EDWARD: Yeah. I imagine most people listening to this have tried lots of different pieces of software and found them great, or terrible, or somewhere in between. And I don't think there's necessarily one way to do this. But I think my way has been to try lots of things, unsurprisingly, and evaluate them based on the thing that I'm trying to do. Sometimes I'll go into a new field, or a new area, or a new product, or whatever, and you just sort of use what's there, or what people have told you about, or what you heard about last, and that's fine. That's a great place to start, right? And then you start seeing maybe where it falls down, or where it is frustrating or doesn't quite meet those needs. And it takes a bit of stepping back. Again, I don't think I'm, like, going to blow anyone's mind here by this amazing secretive technique that I have for, like, discovering good software. But it's, like, sitting there and going through this iterative loop of try it, evaluate it. Be honest with, is it meeting or not meeting some particular needs? And then try something else. Or now you have a little more info to arm yourself to get to the next piece that is potentially good. As you go on in your career and you've tried many, many, many pieces of things, you start to see patterns, right? And you know, like, oh, it's not like, oh, this is how I make websites. It's like, ah, I understand that websites are made with a combination of HTML, and CSS, and JavaScript and sometimes use frameworks. And there's a database layer with an ORM. And you start to understand all the different parts. And now that you have those keywords and those pieces a little more under your control or you have more experience with them, you can use all that experience to then seek out particular pieces. I'm looking for an ORM that's built with Rust because that's the thing I need to do it for; that's the platform I need to work with. And I needed to make sure that it supports MySQL and Postgres, right? Like, it's a very targeted thing that you wouldn't know when you're starting out. But over years of experience, you understand the difference and the reasons why you might need something like that. And sometimes it's about kind of evaluating options and maybe making little test projects to play around with those things or side projects. That's why something like investment time or 20% time is so helpful and useful for that if you're the kind of person who, you know, enjoys programming on your own in your own free time like I am. And that's also a great time to do it, although it's certainly not required. And so, that's kind of how I go through and evaluate whatever tool it is that I need. For something maybe more professional or higher stakes, there's a little more evaluation upfront, right? You want to make sure you make the right choice before you spend thousands of hours using it and potentially regretting [laughs] it and having to roll it back, causing even more thousands of hours of time. So, there's obviously some scrutiny there. But, again, that also takes experience and understanding the kind of need that you have. So, yeah, it's kind of a trade-off of, like, your time, and your energy, and your experience, and your interest. You will have many different inputs from colleagues, from websites, from posts on the internet, from Twitter, or fediverse-type kind of blogging and everything in between, right? So, you take all that in, and you try a bunch of stuff, and you come out on the other side, and then you do it again. STEPHANIE: Yeah, it sounds like you really like to just experiment, and I think that's really great. And I actually have to say that I am not someone who likes to do that [laughs]. Like, it's not where I focus a lot of my time. And it's why I'm, like, glad I'm friends with you, first of all. EDWARD: [laughs] STEPHANIE: But also, I've realized I'm much more of, like, a gatherer in terms of information and opinions. Like, I like hearing about other people's experience to then, like, help inform an opinion that I might develop myself. And, you know, it's not to say that, like, I am, like, oh yeah, like, so and so said this, and so, therefore, yeah, I completely believe what they have to say. But as someone who does not particularly want to spend a ton of my time trying out things, it is really helpful to know people who do like to do that, know people who I do trust, right? And then kind of like you had mentioned, just, like, having all these different inputs. And one thing that has changed for me with more experience is, previously, a lot of, like, the basis of what I thought was the quote, unquote, "right way" to develop software was, like, asking, like, other people and, you know, their opinions becoming my own. And, you know, at some point, though, that, like, has shifted, right? Where it's like, oh, like, you know, I remember learning this from so and so, and, like, actually, I think I disagree now. Or maybe it's like, I will take one part of it and be like, yeah, I really like test-driven development in this particular way that I have figured out how I do it, but it is different still from, like, who I learned it from. And even though, like, that was kind of what I thought previously as, like, oh yeah, like, this is the way that I've adopted without room for adjustment. I think that has been a growth, I guess, that I can point to and be like, oh yeah, like, I once was in a position where maybe opinions weren't necessarily my own. But now I spend a lot more time thinking about, like, oh, like, how do I feel about this? And I think there is, like, some amount of self-reflection required, right? A lot, honestly. Like, you try things, and then you think about, like, did I like that? [laughs] One without the other doesn't necessarily fully informed opinion make. EDWARD: Yeah, absolutely. I mean, I'm really glad you brought up that, like, you've heard an opinion, or a suggestion, or an idea from somebody, and you kind of adopt it as your own for a little bit. I like to think of it as trying on ideas like you try on clothing. Or something like, let me try on this jacket. Does this fit? And maybe you like it a little bit. Or maybe you look ridiculous, and it's [laughs] not quite for you. And you don't feel like it's for you. But you have to try. You have to, like, actually do it. And that is a completely valid way to, like, kick-starting some of those opinions, getting input from friends or colleagues, or just the world around you. And, like, hearing those things and trying them is 100% valid. And I'm glad you mentioned that because if I mentioned it, I think I kind of skipped over it or went through it very quickly. So, absolutely. And you're talking about how you just take, like, one part of it maybe. That nuance, that is, I think, really critical to that whole thought, too. Everything works differently for different people. And every tool is good for other, like, different jobs. Like, it will be like saying a hammer is the best tool, and it's, like, well, it's a good tool for the right thing. But, like, I wouldn't use a hammer to, like, I don't know, level the new house numbers I put on my house, right? But I might use them to, like, hit the nail to get them in. So, it's a silly analogy, but, like, there is always nuance and different ways to apply these different tools and opinions. STEPHANIE: I like that analogy. I think it would be really funny if there was someone out there who claimed that the hammer is the best tool ever invented [laughs]. EDWARD: Oh, I'm sure. I'm sure there is, you know. I'm not going to use a drill to paint my house, though [laughs]. STEPHANIE: That's a fair point, and you don't have to [chuckles]. EDWARD: Thank you [laughs]. STEPHANIE: But, I guess, to extend this thought further, I completely and wholeheartedly agree that, like, yeah, everyone gets to decide for themselves what works for them. But also, we work in relation with others. And I'm very interested in the balance of having your own ideas and opinions about tooling, software practices, like, whatever, and then how to bring that back into, like, working on a team or, like, working with others. EDWARD: Yeah. Well, I don't know if this is exactly what you're asking, but it makes me think of: you've gone off; you've discovered a whole bunch of stuff that you think works really well for you. And then you go to work, or you go to a community that is using a very different way of working, or different tools, or different technologies. That can be a piece of friction sometimes of, like, "Oh my gosh, I love Ruby on Rails. It's the best." And someone else is like, "I really, really don't like Ruby on Rails for reasons XYZ. And we don't use it here." And that can be really tough and, honestly, sometimes even disheartening, depending on how strongly you feel about that tool and how strongly they feel about their tools. And as a young developer many years ago, I definitely had a lot more of my identity wrapped up in the tools and technologies that I used. And that has been very useful to try to separate those two. I don't claim to be perfect at it or done with that work yet. But the more I can step away and say, you know, like, this is only a tool. It is not the tool. It is not the best tool. It is a tool that can be very effective at certain things. And I've found, at least right now, the more useful thing is to get to the root of the problem you're trying to solve and make sure you agree with everybody on that premise. So, yes, you may have come from a world where fast iteration and a really fluent language interface like Ruby has and a really fast iteration cycle like Rails has, is, like, the most important need to be solved because other things have been solved. You understand what you're doing for your product, or maybe you need to iterate quickly on that product. You've figured out an audience. You're getting payroll. You're meeting all that as a business. But then you go into a business that's potentially, like, let's say, much less funded. Or they have their market fit, and now they're working on, like, extreme performance optimization, or they're working on getting, like, government compliance, or something like that. And maybe Rails is still great. This is maybe a...the analogy may fall apart here. But let's pretend it isn't for some reason. You have to agree that, hey, like, yes, we've solved problem X that Rails really helps you solve. And now we're moving on to problem Y, and Rails may not help you solve that, or whatever technology you're using may not help you solve that. And I've found it to be much more useful to stop worrying about the means, and the tools, the things in between, and worry about the ends, worry about the goal, worry about the problems you're actually trying to solve. And then you can feel really invested in trying to solve that problem together as a group, as a team, as a community. I've found that to be very helpful. And I would also like to say it is extremely difficult to let some of that stuff go. It takes a lot of work. I see you nodding along. Like, it's really, really hard. And, like I said, I'm not totally done with it either. But that's, I think, it's something I'm really working on now and something I feel really strongly about. STEPHANIE: Yeah. You mentioned the friction of, like, working in an environment where there are different opinions, which is, you know, I don't know, just, like, reality, I guess [laughs]. EDWARD: Human nature. STEPHANIE: Yeah, exactly. And one thing I was thinking about recently was, like, okay, like, so someone else maybe made a decision about using a type of technology or, like, made a decision about architecture before my time or, like, above me, or whatever, right? Like, I wasn't there, and that is okay. But also, like, how do I maintain what I believe in and hold fast to, like, my opinions based on my value system, at least, without complaining? [laughs] Because I've only seen that a little bit before, right? When it just becomes, like, venting, right? It's like, ugh, like, you know, I have seen people who are coming from maybe, like, microservices or more of a JavaScript world, and they're like, ugh, like, what is going on with Rails? Like, this sucks [laughs]. And one thing I've been trying lately is just, like, communicating when I don't agree that something's a great idea. But also, like, acknowledging that, like, yeah, but this is how it is for this team, and I'm also not in a position to change it. Or, like, I don't feel so strongly about it that I'm like, "Hey, we should totally rethink using this, like, background job [laughs] platform." But I will be like, "Hey, like, I don't like this particular thing about it. And, you know, maybe here are some things that I did to mitigate whatever thing I'm not super into," or, like, "If I had more time, this is what I would do," and just putting it out there. Sometimes, I don't get, like, engagement on it. But it's a good practice for me to be, like, this is how I can still have opinions about things, even if I'm not, at least in this particular moment, in a position to change anything. EDWARD: It sounds to me like you in, at least at the lowest level, like, you want to be acknowledged, and you want to, like, be heard. You want to be part of a process. And yes, it doesn't always go with Stephanie's initial thought, or even final thought, or Edward's final thought. But it is very helpful to know that you are heard and you are respected. And it isn't someone just, like, completely disregarding any feeling that you have. As much as we like to say programming is this very, like, I don't know, value neutral, zero emotion kind of job, like, there's tons of emotion in this job. We want to do good things for the world. We want our technology to serve the people, ultimately, at least I do, and I know you do. But we sometimes disagree on the way to do that. And so, you want to make sure you're heard. And if you can't get that at work, like, and I know you do this, but I would encourage anyone listening out there to, like, get a buddy that you can vent to or get somebody that you can express, and they will hear you. That is so valuable just as a release, in some ways, to kind of get through what you need to get through sometimes. Because it is a job, and you aren't always the person that's going to make the decisions. And, honestly, like, you do still have one decision left, which is you can go work somewhere else if it really is that bad. And, like, it's useful to know that you are staying where you are because you appreciate the trade-offs that you have: a steady paycheck, or the colleagues that you work with, or whatever. And that's fine. That's an okay trade-off. And at some point, you might want to make a different trade-off, and that's also fine. We're getting real managery and real here. But I think it's useful. Like you said, this can be a very emotional career, and it's worth acknowledging that. STEPHANIE: Yeah, you just, you know, raised a bunch of, like, very excellent points. Yeah, at the end of the day, like, you know, you can do your best to, like, propose changes or, like, introduce new tooling and, like, see how other people feel about it. But, like, yeah, if you fundamentally do not enjoy working with a critical tool that, you know, a lot of the foundation of the work that you're doing day to day is built off of, then maybe there is a place where, like, another company that's using tools that you do feel excited or, like, passionate or, like, are a better alignment with what you hope to be doing. Kind of just going back to that theme that we were talking about earlier, like, everyone gets to decide for themselves, right? Like, the tools to help them do what they want to be doing. EDWARD: And you could even, like, reframe it for yourself, where instead of it being about the tools, maybe it's about the problem. Like, you start being more invested in, like, the problem that you're solving and, okay, maybe you don't want to use microservices or whatever, but, like, maybe you can get behind that if you realign yourself. The thing you're trying to solve is not the tool. The thing you're trying to solve is the problem. And that can be a useful, like, way to mitigate that or to, like, help yourself feel okay about the thing, whatever that is. STEPHANIE: Yeah. Now, how do I have this conversation with everyone [laughter] who claims on the internet that X is the solution to all their problems or the silver bullet, [laughs] or whatever? EDWARD: Yeah, that's tough because there are some very strong opinions on the internet, as I'm sure [laughs] you've observed. I don't know if I have the answer [laughs]. Once again, nuance and indecisions. I have been currently approaching it from kind of a meta-perspective of, like, if someone says, "X is the best tool," you know, "A hammer is the best tool," right? I'm not going to go write the post that's like, "No, hammer is, in fact, not the best tool. Don't use hammers." I would maybe instead write a post that's like, "Consider what makes the best tool." I've effectively, like, raised up one level of abstraction from, we're no longer talking about is X, or Y, or Z, the best tool? We're talking about how do we even decide that? How do we even think about that? One post...I'm now just promoting my blog posts, so get ready. But one thing I wrote was this post called And Not But. And I tried to make the case that instead of saying the word but in a sentence, so, like, yeah, yeah, we might want to use hammers, but we have to use drills or whatever. I'm trying to make the case that you can use and instead. So yeah, hammers are really good, and drills are really good in these other scenarios. And trying to get that nuance in there, like, really, really putting that in there and getting people to, like, feel that better, I think, has been really helpful, for me, certainly to get through. And part of the best thing about writing a blog post is just getting your own thoughts...I mean, it's another way to vent, right? It's getting your own thoughts out somewhere. And sometimes people respond to them. You'd be surprised who just reaches out and been like, "Hey, yeah, like, I really appreciated that post. That was really great." You weren't trying to reach that person, but now you have another connection. So, a side benefit for writing blog posts [inaudible 30:17] do it, or just even getting your thoughts out via a podcast, via a video, whatever. So, I've kind of addressed that. I also wrote a post when I worked at thoughtbot called Empathy Online. And that came out of, like, frustration with seeing people being too divisive or, in my opinion, unempathetic or inconsiderate. And instead of, again, trying to just say, "Stop it, don't do that," [laughs] but trying to, like, help use what I have learned when communicating in a medium that is kind of inherently difficult to get across emotion and empathy. And so, again, it's, in some ways, unsatisfying because what you really want to do is go talk to that person that says, "Hammer is the best tool," and say, "No, stop it [laughs]," and, like, slap them on the head or whatever, politely. But I think that probably will not get you very far. And so, if your goal, really, is to change the way people think about these things, I find it way more effective to, like, zoom out and talk about that on that sort of more meta-level and that higher level. STEPHANIE: Yeah. I liked how you called it, like, a higher level of abstraction. And, honestly, the other thing I was thinking about as you were talking about the, like, divisiveness that opinions can create, there's also some aspect of it, as a reader, realizing that one person sharing their opinion does not take away your ability to have a differing opinion [laughs]. And sometimes it's tough when someone's like, "Tailwind sucks [laughs], and it is a backward step in, you know, how we write CSS," or whatever. Yes, like, sometimes that can be kind of, like, inflammatory. But if you, like, kind of are translating it or, like, reading between the lines, they're just writing about their perspective from the things that they value. And it is okay for you to value different things and, for that reason, have a different perspective on the same thing. And, I don't know, that has helped me sometimes avoid getting into that, like, headspace of wanting to argue with someone [laughs] on the internet. Or they'll be like, "This is why I am right." [laughs] Now I have to write something and share it on the internet in response [laughs]. EDWARD: There's this idea of the narcissism of minor differences. And I believe the idea is this, like, you know, you're more likely to argue with someone who, like, 90% agrees with you. But you're just, like, quibbling over that last 10%. I mean, one might call it bikeshedding. I don't know if you've heard that phrase. But the thing that I have often found, too, is that, like the GitHub post, I will get people arguing with me, like, there's the kind of stuff I expected, where it's like, "Oh, but GitHub is really good," and XYZ and that's fine. And we can have that conversation. But it's kind of surprising, and I should have expected it, that people will sometimes be like, "Hey, you didn't go far enough. You should tell people to, like, completely delete their GitHub or, like, you know, go protest in the street." And, like, maybe that's true. I'm not saying it is or isn't. But I think one thing I try to think about is, in any post, in any trying convincing argument, like, you're potentially moving someone 1 step forward, even if there's ten steps to go. But they're never going to make those ten steps if they don't make the first 1. And so, you can kind of help them get there. And someone else's post can absolutely take them from step 5 to 6 or 6 to 7 or 7 to 8. And you won't accomplish it all at once, and it's kind of a silly thing to try, and your efforts are probably lost [laughs]. Unfortunately, it's a little bit of preaching to the choir because, like, yeah, the people that are going to respond to, like, the extreme, the end are, like, the people that already get it. And the people that you're trying to convince and move along are not going to get that thing. I do want to say that I could see this being perceived as, like, a very privileged position of, like, if there's some, like, genuine atrocity happening in the world, like, it is appropriate to go to extremes many times and sometimes, and that's fine, and people are allowed to be there. I don't want to invalidate that. It's a really tricky balance. And I'm trying to say that if your goal is to vent, that's fine. And if your goal is to move people from step 3 to 4, you have to meet people at step 3. And all that's valid and okay to try to help people move in that way. But it is very tricky. And I don't want to invalidate someone who's extremely frustrated because they're at step 10, and no one else is seeing the harm that not everybody else being at step 10 is. Like, that's an incredibly reasonable place to be and an okay place to be. STEPHANIE: Yeah, yeah. The other thing you just sparked, for me, is also the, like, power of, yeah, being able to say like, "Yeah, I agree with this 50%, or 60%, or, like, 90%." And also, there's this 10% that I'm like, oh, like, I wish were different, or I wish they'd gone further, or I wish they didn't say that. Or, you know, I just straight up disagree with this step 1 sentence, but the rest of the article, you know, I really related to. And, like, teasing that apart has been very useful for me, right? Because then I'm no longer like being like, oh, was this post good or bad? Do I agree with it or don't agree with it? It's like, there's room for [laughs] all of it. EDWARD: Yeah, that's that nuance that, you know, I liked this post, and I did not agree with these two parts of it, or whatever. It's so useful. STEPHANIE: Well, thanks, Edward, so much for coming on the show and bringing that nuance to this conversation. I feel really excited about kind of what we talked about, and hopefully, it resonates with some of our listeners. EDWARD: Yeah, I hope so too. I hope I can take them from step 2 to step 3 [laughs]. STEPHANIE: On that note, shall we wrap up? EDWARD: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeeee!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at tbot.io/referral. Or you can email us at referrals@thoughtbot.com with any questions.
Joël got to do some pretty fancy single sign-on work. And when it came time to commit, he documented the ridiculous number of redirects to give people a sense of what was happening. Stephanie has been exploring Rails callbacks and Ruby debugging tools, using methods like save_callbacks and Kernel.caller, and creating a function call graph to better understand and manage complex code dependencies. Stephanie is also engaged in an independent project and seeking strategies to navigate the challenges of solo work. She and Joël explore how to find external support and combat isolation, consider ways to stimulate creativity, and obtain feedback on her work without a direct team. Additionally, they ponder succession planning to ensure project continuity after her involvement ends. They also reflect on the unique benefits of solo work, such as personal growth and flexibility. Stephanie's focus is on balancing the demands of working independently while maintaining a connected and sustainable professional approach. ASCII Sequence Diagram Creator (https://textart.io/sequence) Callback debugging methods (https://andycroll.com/ruby/find-list-debug-active-record-callbacks-in-the-console/) Kernel.caller (https://ruby-doc.org/core-3.0.2/Kernel.html#method-i-caller) Method.source_location (https://ruby-doc.org/core-3.0.2/Method.html#method-i-source_location) Building web apps by your lonesome by Jeremy Smith (https://www.youtube.com/watch?v=Rr871vmV4YM) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: I got to do something really fun this week, where I was doing some pretty fancy single sign-on work. And when it came time to commit, I wanted to document the kind of ridiculous number of redirects that happen and give people a sense of what was going on. And for my own self, what I had been doing is, I had done a sequence diagram that sort of shows, like, three different services that are all talking to each other and where they redirect to each other as they all go through the sequence to sign someone in. And I was like, how could I embed that in the commit message? Because I think it would be really useful context for someone trying to get an overview of what this commit is doing. And the answer, for me, was, can I get this sequence diagram in ASCII form somewhere? And I found a website that allows me to do this in ASCII art. It's the textart.io/sequence. And that allows me to create a sequence diagram that gets generated as ASCII art. I can copy-paste that into a commit message. And now anybody else who is like, "What is it that Joël is trying to do here?" can look at that and be like, "Oh, oh okay, so, we got these, like, four different places that are all talking to each other in this order. Now I see what's happening." STEPHANIE: That's super neat. I love the idea of having it directly in your commit message just because, you know, you don't have to go and find a graph elsewhere if you want to understand what's going on. It's right there for you, for future commit explorers [laughs] trying to understand what was going on in this snippet of time. JOËL: I try as much as possible to include those sorts of things directly in the commit message because you never know who's reading the commit. They might not have access to some sort of linked resource. So, if I were like, "Hey, go to our wiki and see this link," like, sure, that would be helpful, but maybe the person reading it doesn't have access to the wiki. Maybe they do have access, but they're not on the internet right now, and so they don't have access to the wiki. Maybe the wiki no longer exists, and that's a dead link. So, as much as possible, I try to embed context directly in my commit messages. STEPHANIE: That's really cool. And just another shout out to ASCII art, you know [laughs], persevering through all the times with our fancy tools. It's still going strong [laughs]. JOËL: Something about text, right? STEPHANIE: Exactly. I actually also have a diagram graph thing to share about what's new in my world that is kind of in a similar vein. Another thoughtboter and former guest on the show, Sara Jackson, shared in our dev channel about this really cool mural graph that she made to figure out what was going on with callbacks because she was working on, you know, understanding the lifecycle of this model and was running into, like, a lot of complex behavior. And she linked to a really neat blog post by Andy Croll, too, that included a little snippet sharing a few callback debugging methods that are provided by ActiveRecord. So, basically, you can have your model and just call double underscore callbacks. And it returns a list of all the callbacks that are defined for that model, and I thought that was really neat. So, I played around with it and copypastad [laughs] the snippet into my Rails console to figure out what's going on with basically, like, the god object of that that I work in. And the first issue I ran into was that it was undefined because it turns out that my application was on an older [laughs] version of Rails than that method was provided on. But, there are more specific methods for the types of callbacks. So, if you are looking specifically for all the callbacks related to a save or a destroy, I think it's save underscore callbacks, right? And that was available on the Rails version I was on, which was, I think, 4. But that was a lot of fun to play around with. And then, I ended up chatting with Sara afterwards about her process for creating the diagram after, you know, getting a list of all these methods. And I actually really liked this hybrid approach she took where, you know, she automated some parts but then also manually, like, went through and stepped through the code and, like, annotated notes for the methods as she was traversing them. And, you know, sometimes I think about, like, wow, like, it would be so cool if this graph just generated automatically, but I also think there is some value to actually creating it yourself. And there's some amount of, like, mental processing that happens when you do that, as opposed to, like, looking at a thing that was just, you know, generated afterwards, I think. JOËL: Do you know what kind of graph Sara generated? Was it some kind of, like, function call graph, or was it some other way of visualizing the callbacks? STEPHANIE: I think it was a function call graph, essentially. It even kind of showed a lot of the dependencies, too, because some of the callback functions were quite complicated and then would call other classes. So, there was a lot of, I think, hidden dependencies there that were unexpected, you know, when you think you're just going to create a regular old [laughs] record. JOËL: Yeah, I've been burned by unexpected callbacks or callbacks that do things that you wouldn't want in a particular context and then creating bad data or firing off external services that you really didn't want, and that can be an unpleasant surprise. I appreciate it when the framework offers debugging tools and methods kind of built-in, so these helpers, which I was not aware of. It's really cool because they allow you to kind of introspect and understand the code that you're going through. Do you have any others like that from Rails or Ruby that you find yourself using from time to time to help better understand the code? STEPHANIE: I think one I discovered recently was Kernel.caller, which gives you the stack trace wherever you are when executing. And that was really helpful when you're not raising an exception in certain places, and you need to figure out the flow of the code. I think that was definitely a later discovery. And I'm glad to have it in my back pocket now as something I can use in any kind of Ruby code. JOËL: That can, yeah, definitely be a really useful context to have even just in, like, an interactive console. You're like, wait a minute, where's this coming from? What is the call stack right now? STEPHANIE: Do you have any debugging tools or methods that you like to use that maybe are under the radar a little bit? JOËL: One that I really appreciate that's built into Ruby is the source location method on the method object, so Ruby has a method object. And so, when you're dealing with some sort of method and, like, maybe it got generated programmatically through metaprogramming, or maybe it's coming from a gem or something like that, and you're just like, where is this define? I'm trying to find it. If you're in your editor and you're doing stuff, maybe you could run some sort of search, or maybe it has some sort of keyword lookup where you can just find the definition of what's under your cursor. But if you're in an interactive console, you can create a method object for that method name and then call dot source location on it. And it will tell you, here's where it's defined. So, very handy in the right circumstances. STEPHANIE: Awesome. That's a great tip. JOËL: Of course, one of the most effective debugging tools is having a pair, having somebody else work with you, but that's not always something that you have. And you and I were talking recently about what it's like to work solo on a project. Because you're currently on a project, you're solo, at least from the thoughtbot side of things. You're embedding with a team, with a client. Are you working on kind of, like, a solo subtask within that, or are you still kind of embedding and interacting with the other teammates on a regular basis? STEPHANIE: Yeah. So, the past couple of weeks, I am working on more of a solo initiative. The other members of my client team are kind of ramping up on some other projects for this next quarter. And since my engagement is ending soon, I'm kind of left working on some more residual tasks by myself. And this is new for me, actually. I've not really worked in a super siloed by-myself kind of way before. I usually have at least one other dev who I'm, like, kind of partnering up with on a project, or an epic, or something like that. And so, I've had a very quiet week where no one is, you know, kind of, like, reaching out to me and asking me to review their code, or kind of checking in, or, you know, asking me to check in with them. And yeah, it's just a little bit different than how I think I like to normally work. I do like to work with other people. So, this week has been interesting in terms of just kind of being a more different experience where I'm not as actively collaborating with others. JOËL: What do you think are some of the biggest challenges of being kind of a little bit out in your own world? STEPHANIE: I think the challenges for me can definitely be the isolation [laughs], and also, what kind of goes hand in hand with that is when you need help, you know, who can you turn to? There's not as much of an obvious person on your team to reach out to, especially if they're, like, involved with other work, right? And that can be kind of tough. Some of the other ones that I've been thinking about have been, you know, on one hand, like, I get to make all of the decisions that I want [laughs], but sometimes you kind of get, like, really in your own head about it. And you're not in that space of, like, evaluating different solutions that you maybe might not think of. And I've been trying to figure out how to, like, mitigate some of that risk. JOËL: What are some of the strategies that you use to try to balance, like making good decisions when you're a bit more solo? Do you try to pull in someone from another team to talk ideas through? Do you have some sort of internal framework that you use to try to figure out things on your own? What does that look like? STEPHANIE: Yeah, luckily, the feature I'm working on is not a huge project. Well, if it were, I think then I wouldn't be alone on it. But, you know, sometimes you find yourself kind of tasked with one big thing for a while, and you are responsible for from start to finish, like all of the architectural decisions to implementation. But, at least for me, the scope is a little more narrow. And so, I don't feel as much of a need to get a lot of heads together because I at least feel somewhat confident in what I'm doing [laughs]. But I have found myself being a bit more compelled to kind of just verbalize what I'm doing more frequently, even to, like, myself in Slack sometimes. It's just like, I don't know who's reading this, but I'm just going to put it out there because maybe someone will see this and jump in and say, "Oh, like, interesting. Here's some other context that I have that maybe might steer you away from that," or even validating what I have to say, right? Like, "That sounds like a good idea," or, you know, just giving me an emoji reaction [laughs] is sometimes all I need. So, either in Slack or when we give our daily sync updates, I am, I think, offering a little more details than I might if I already was working with someone who I was more in touch with in an organic way. JOËL: And I think that's really powerful because it benefits you. Sort of by having to verbalize that or type it out, you, you know, gain a little bit of self-awareness about what you're trying to do, what the struggles are. But also, it allows anybody else who has potentially helpful information to jump in. I think that's not my natural tendency. When I'm on something solo, I tend to kind of, like, zoom in and focus in on something and, like, ignore a little bit of the world around me. Like, that's almost the time when I should look at overcommunicating. So, I think most times I've been on something solo, I sort of keep relearning this lesson of, like, you know, it's really important to constantly be talking out about the things that you're doing so that other people who are in a broader orbit around you can jump in where necessary. STEPHANIE: Yeah, I think you actually kind of touched on one of the unexpected positives, at least for me. Something I wasn't expecting was how much time I would have to just be with my thoughts. You know, as I'm implementing or just in my head, I'm mulling over a problem. I have less frequent, not distractions necessarily, but interruptions. And sometimes, that has been a blessing because I am not in a spot where I have a lot of meetings right now. And so, I didn't realize how much generative thought happens when you are just kind of, like, doing your own thing for a little bit. I'm curious, for you, is that, like, a space that you enjoy being when you're working by yourself? And I guess, you know, you were saying that it's not your natural state to kind of, like, share what's going on until maybe you've fully formed an idea. JOËL: I think I often will regret not having shared out before everything is done. The times that I have done it, I've been like, that was a really positive experience; I should do that more. I think it's easy to sort of wait too long before sharing something out. And with so many things, it feels like there's only one more small task before it's done. Like, I just need to get this one test to go green, and then I can just put up a PR, and then we'll have a conversation about it. But then, oh, this other test broke, or this dependency isn't installing correctly. And before you know it, you've spent a whole day chasing down these things and still haven't talked. And so, I think if some of those things were discussed earlier, it would help both to help me feel more plugged in, but also, I think everybody else feels like they're getting a chance to participate as well. STEPHANIE: So, you mentioned, you know, obviously, there's, like, the time spent just arriving at the solution before sharing it out for feedback. But have you ever been in a position where there is no one to give you feedback and, like, not even a person to review your code? JOËL: That's really challenging. So, occasionally, if I'm working on a project, maybe it would be, like, very early-stage startup that maybe just has, like, a founder, and then I'm, like, the only technical person on the team, generally, what I'll try to do is to have some kind of review buddy within thoughtbot, so some other developer who's not staffed on my project but who has access to the code such that I can ask them to say, "Hey, can you just take a look at this and give me a code review?" That's the ideal situation. You know, some companies tend to lock things down a lot more if you're dealing with something like healthcare or something like that, where there might be some concerns around personal information, that kind of thing. But generally, in those cases, you can find somebody else within the company who will have some technical knowledge who can take a look at your code; at least, that's been my experience. STEPHANIE: Nice. I don't think I've quite been in that position before; again, I've really mostly worked within a team. But there was a conference talk I watched a little bit ago from Jeremy Smith, and it was called Building Web Apps by Your Lonesome. And he is a, like, one-man agency. And he talked about, you know, what it's like to be in that position where you pretty much don't have other people to collaborate with, to review your code. And one thing that he said that I really liked was shifting between writer and editor mode. If you are the person who has to kind of just decide when your code is good enough to merge, I like that transition between, like, okay, I just spent however many hours putting together the solution, and now I'm going to look at it with a critical eye. And sometimes I think that might require stepping away for a little bit or, like, revisiting it even the next day. That might be able to help see things that you weren't able to notice when you were in that writing mode. But I have found that distinction of roles really helpful because it does feel different when you're looking at it from those two lenses. JOËL: I've definitely done that for some, like, personal solo projects, where I'm participating in a game jam or something, and then I am the only person to review my code. And so, I will definitely, at that point, do a sort of, like, personal code review where I'll look at it. Maybe I'm doing PRs on GitHub, and I'm just merging. Maybe I'm just doing a git diff and looking at a commit in the command line on my own machine. But it is useful, even for myself, to sort of switch into that editor mode and just kind of look at everything there and say, "Is it in a good place?" Ideally, I think I do that before putting it out for a co-worker's review, so you kind of get both. But on a solo project, that has worked actually pretty well for me as well. STEPHANIE: One thing that you and I have talked about before in a different context, I think, when we have chatted about writing conference talks, is you are really great about focusing on the audience. And I was thinking about this in relation to working solo because even when you are working by yourself on a project, you're not writing the code for yourself, even though you might feel like [laughs] it in the moment. And I also kind of like the idea of asking, like, who are you building for? You know, can you ask the stakeholder or whoever has hired you, like, "Who will maintain this project in the future?" Because likely, it won't be you. Hopefully, it won't be you unless that's what you want to be doing. There's also what my friend coined the circus factor as opposed to the bus factor, which is, like, if you ran away to the circus tomorrow [laughs], you know, what is the impact that would have? And yeah, I think working solo, you know, some people might think, like, oh, that gives me free rein to just write the code exactly how I want to, how I want to read it. But I think there is something to be said about thinking about the future of who will be [inaudible 18:10] what you just happen to be working on right now. JOËL: And keep in mind that that person might be future you who might be coming back and be like, "What is going on here?" So, yeah, audience, I think, is a really important thing to keep in mind. I like to ask the question, if somebody else were looking at this code, and somebody else might be future me, what parts would they be confused by? If I was walking somebody else through the code for the first time, where would they kind of stop me through the walkthrough and be like, "Hey, why is this happening? What's the connection between these two things? I can see they're calling each other, but I don't know why." And that's where maybe you put in a comment. Maybe you find a better method or a class name to better explain what happens. Maybe you need to put more context in a commit message. There's all sorts of tools that we can use to better increase documentation. But having that pause and asking, "What will confuse someone?" is, I think, one of the more powerful techniques I do when I'm doing self-review. STEPHANIE: That's really cool. I'm glad you mentioned that, you know, it could also be future you. Because another thing that Jeremy says in this talk that I was just thinking about is the idea of optimizing for autonomy. And there's a lot to be said there because autonomy is like, yeah, like, you end up being the person who has to deal with problems [laughs], you know, if you run into something that you can't figure out, and, ideally, you'll have set yourself up for success. But I think working solo doesn't mean that you are in your own universe by yourself completely. And thinking about future, you, too, is kind of, like, part of the idea that the person in this moment writing code will change [laughs]. You'll get new information. Maybe, like, you'll find out about, like, who might be working on this in the future. And it is kind of a fine balance between making sure that you're set up to handle problems, but at the same time, maybe it's that, like, you set anyone up to be able to take it away from where you left it. JOËL: I want to take a few moments to sort of talk a little bit about what it means to be solo because I think there are sort of multiple different solo experiences that can be very different but also kind of converge on some similar themes. Maybe some of our listeners are listening to us talking and being like, "Well, I'm not at a consultancy, so this never happens to me." But you might find yourself in that position. And I think one that we mentioned was maybe you are embedded on a team, but you're kind of on a bit of a larger project where you're staffed solo. So, even though you are part of a larger team, you do feel like the initiative that you're on is siloed to you a little bit. Are there any others that you'd like to highlight? STEPHANIE: I think we also mentioned, you know, if you're a single developer working on an application because you might be the first technical hire, or a one-person agency, or something, that is different still, right? Because then your community is not even your company, but you have to kind of seek out external communities on social networks, or Slack groups, or whatever. I've also really been interested in the idea of developers kind of being able to be rotated with some kind of frequency where you don't end up being the one person who knows everything about a system and kind of becomes this dependency, right? But how can we make projects so, like, well functioning that, like, anyone can step in to do some work and then move on? If that's just for a couple of weeks, for a couple of months. Do you have any thoughts about working solo in that kind of situation where you're just stepping into something, maybe even to help someone out who's, you know, on vacation, or kind of had to take an unexpected leave? JOËL: Yeah, that can be challenging. And I think, ideally, as a team, if you want to make that easier, you have to set up some things both on a, like, social level and on a tactical level, so all the classic code quality things that you want in place, well structured, encapsulated code, good documentation, things like that. To a certain extent, even breaking down tasks into smaller sort of self-sufficient stories. I talk a lot about working incrementally. But it's a lot easier to say, "Hey, we've got this larger story. It was broken down into 20 smaller pieces that can all be shipped independently, and a colleague got three of them done and then had to go on leave for some reason. Can you step in and do stories 4 through 20?" As opposed to, "Hey, we have this big, amorphous story, and your colleague did some work, and it kind of is done. There's a branch with some code on it. They left a few notes or maybe sent us an email. But they had to go on leave unexpectedly. Can you figure it out and get it done?" The second scenario is going to be much more challenging. STEPHANIE: Yeah, I was just thinking about basically what you described, right? Where you might be working on your own, and you're like, well, I have this one ticket, and it's capturing everything, and I know all that's going on [laughs], even though it's not quite documented in the ticket. But it's, you know, maybe on my branch, or in my head, or, worst of all, on my local machine [laughs] without being pushed up. JOËL: I think maybe that's an anti-pattern of working solo, right? A lot of these disciplines that you build when you're working in a team, such as breaking up tickets into smaller pieces, it's easy to kind of get a little bit lazy with them when you're working solo and let your tickets inflate a little bit, or just have stuff thrown together in branches on your local machine, which then makes it harder if somebody does need to come in to either collaborate with you or take over from you if you ever need to step aside. STEPHANIE: Right. I have definitely seen some people, even just for their personal projects, use, like, a Trello board or some other project management tool. And I think that's really neat because then, you know, obviously, it's maybe just for their own, like, self-organization needs, but it's, like, that recognition that it's still a complicated project. And just because they're working by themselves doesn't mean that they can't utilize a tool for project management that is meant for teams or not even teams [laughs], you know, people use them for their own personal stuff all the time. But I really like that you can choose different levels of how much you're documenting for your future self or for anyone else. You had mentioned earlier kind of the difference between opening up a PR for you...you have to merge your branch into main or whatever versus just committing to main. And that distinction might seem, like, if you were just working on a personal project, like, oh, you know, why go through the extra step? But that can be really valuable in terms of just seeing, like, that history, right? JOËL: I think on solo projects, it can really depend on the way you tend to treat your commit history. I'm very careful with the history on the main branch where I want it to tell a sort of, like, cohesive story. Each commit is kind of, like, crafted a little bit. So, even when I'm working solo and I'm committing directly to master or to the main branch, I'm not just, like, throwing random things there. Ideally, every commit is green and builds and is, like, self-contained. If you don't have that discipline, then it might be particularly valuable to go through the, like, a branching system or a PR system. Or if you just want, like, a place to experiment, just throw a bunch of code together, a bunch of things break; nothing is cohesive, that's fine. It's all a work in progress until you finally get to your endpoint, and then you squash it down, or you merge it, or whatever your workflow is, and then it goes back into the main branch. So, I think that for myself, I have found that, oftentimes, I get not really a whole lot of extra value by going through a branching and PR system when it's, like, a truly solo project, you know, I'm building a side project, something like that. But that's not necessarily true for everyone. STEPHANIE: I think one thing I've seen in other people's solo projects is using a PR description and, you know, having the branching strategy, even just to jot down future improvements or future ideas that they might take with the work, especially if you haven't kind of, like, taken the next step of having that project management system that we talked about. But there is, like, a little more room for some extra context or to, like, leave yourself little notes that you might not want necessarily in your commit history but is maybe more related to this project being, like, a work in progress where it could go in a lot of different directions, and you're figuring that out by yourself. JOËL: Yeah, I mean, definitely something like a draft PR can be a great place to have work in progress and experiment and things like that. Something you were saying got me wondering what distinction you typically have between what you would put in a commit message versus something that you would put in a PR description, particularly given that if you've got, like, a single commit PR, GitHub will automatically make the commit message your PR message as well. STEPHANIE: This has actually evolved for me over time, where I used to be a lot more reliant on PR descriptions holding a lot of the context in terms of the decision-making. I think that was because I thought that, like, that was the most accessible place of information for reviewers to find out, you know, like, why certain decisions were made. And we were using, you know, PR templates and stuff like that. But now the team that I'm working on uses commit message templates that kind of contain the information I would have put in a PR, including, like, motivation for the change, any risks, even deployment steps. So, I have enjoyed that because I think it kind of shortens the feedback loop, too, right? You know, you might be committing more frequently but not, you know, opening a PR until later. And then you have to revisit your commits to figure out, like, okay, what did I do here? But if you are putting that thought as soon as you have to commit, that can save you a little bit of work down the line. What you said about GitHub just pulling your commit message into the PR description has been really nice because then I could just, like, open a thing [laughs]. And that has been nice. I think one aspect that I really like about the PR is leaving myself or reviewers, like, notes via comments, like, annotating things that should not necessarily live in a more permanent form. But maybe I will link to documentation for a method that I'm using that's a little less common or just add some more information about why I made this decision over another at a more granular level. JOËL: Yeah, I think that's probably one of the main things that I tend to put in a PR message rather than the commit message is any sort of extra information that will be helpful at review time. So, maybe it's a comment that says, "Hey, there is a lot of churn in this PR. You will probably have a better experience if you review this in split view versus unified view," things like that. So, kind of, like, meta comments about how you might want to approach reviewing this PR, as opposed to something that, let's say somebody is reviewing the history or is, like, browsing the code later, that wouldn't be relevant to them because they're not in a code review mindset. They're in a, like, code reading, code understanding mindset or looking at the message to say, "Why did you make the changes? I saw this weird method. Why did you introduce that?" So, hopefully, all of that context is in the commit message. STEPHANIE: Yeah, you reminded me of something else that I do, which is leave notes to my future self to revisit something if I'm like, oh, like, this was the first idea I had for the, you know, the way to solve this problem but, you know, note to self to look at this again tomorrow, just in case I have another idea or even to, like, you know, do some more research or ask someone about it and see if they have any other ideas for how to implement what I was aiming for. And I think that is the editor mode that we were talking about earlier that can be really valuable when you're working by yourself to spend a little extra time doing. You know, you are essentially optimizing for autonomy by being your own reviewer or your own critic in a healthy and positive way [laughs], hopefully. JOËL: Exactly. STEPHANIE: So, at the beginning of this episode, I mentioned that this is a new experience for me, and I'm not sure that I would love to do it all of the time. But I'm wondering, Joël, if there are any, you know, benefits or positives to working solo that you enjoy and find that you like to do just at least for a short or temporary amount of time. JOËL: I think one that I appreciate that's maybe a classic developer response is the heads downtime, the focus, being able to just sit down with a problem and a code editor and trying to figure it out. There are times where you really need to break out of that. You need somebody else to challenge you to get through a problem. But there are also just amazing times where you're in that flow state, and you're getting things done. And that can be really nice when you're solo. STEPHANIE: Yeah, I agree. I have been enjoying that, too. But I also definitely am looking forward to working with others on a team, so it's kind of fun having to get to experience both ways of operating. On that note, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeeeeeeee!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at tbot.io/referral. Or you can email us at referrals@thoughtbot.com with any questions.
Stephanie discovered a new book: The Staff Engineer's Path! Joël's got some D&D goodness. Together, they revisit a decade-old blog post initially published in 2013, which discussed the application of Sandi Metz's coding guidelines and whether these rules remain relevant and practiced among developers today. Transcript: JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. STEPHANIE: And I'm Stephanie Minn. And together, we're here to share a bit of what we've learned along the way. JOËL: So, Stephanie, what's new in your world? STEPHANIE: So, I picked up a new book from the library [laughs], which that in itself is not very new. That is [laughs] a common occurrence in my world. But it was kind of a fun coincidence that I was just walking around the aisles of what's new in nonfiction, and staring me right in the face was an O'Reilly book, The Staff Engineer's Path. And I think in the past, I've plugged The Manager's Path by Camille Fournier on the show. And in recent years, this one was published, and it's by Tanya Reilly. And it is kind of, like, the other half of a career path for software engineers moving up in seniority at those higher levels. And it has been a really interesting companion to The Manager's Path, which I had read even though I wasn't really sure I wanted to be manager [laughs]. And now I think I get that, like, accompaniment of like, okay, like, instead of walking that path, like, what does a staff plus engineer look like? And kind of learning a little bit more about that because I know it can be really vague or ambiguous or look very different at a lot of different companies. And that has been really helpful for me, kind of looking ahead a bit. I'm not too far into it yet. But I'm looking forward to reading more and bringing back some of those learnings to the show. JOËL: I feel like at the end of the year, Stephanie, you and I are probably going to have to sit down and talk through maybe your reading list for the year and, you know, maybe shout out some favorites. I think your reading list is probably significantly longer than mine. But you're constantly referencing cool books. I think that would probably be a fun, either end-of-year episode or a beginning-of-year episode for 2024. One thing that's really interesting, though, about the contrast of these two particular books you're talking about is how it really lines up with this, like, fork in the road that a lot of us have in our careers as we get more senior. You either move into more of a management role, which can be a pretty significant departure from what you have to do as a developer, or you kind of go into this, like, ultra-senior individual contributor path. But how that looks day to day can be very different from your sort of just traditional sitting down and banging out tickets. So, it's really cool there's two books looking at both of those paths. STEPHANIE: Yeah, absolutely. And I think the mission that they were going for with these books was to kind of illuminate a little bit more about that fork and that decision because, you know, it can be easy for people to maybe just default into one or the other based on what their organization wants for them without, like, fully knowing what that means. And the more senior you get, the more vague and, like, figure it out yourself [laughs] the work becomes. And it can be very daunting to kind of just be thrown into that and be like, well, I'm in this leadership position now. People are looking to me, and I have all this responsibility, but, like, what do I do? Yeah, so I'm kind of enjoying this book, that is...it's not a technical book, which is actually kind of what I like about it. It's actually more of a leadership book, which is really important for that kind of role. Even though, you know, they are still in that IC track, but it does come with a lot of leadership responsibility. JOËL: Yes, leadership in a very different way than management. But—and this may be counterintuitive for some people, especially earlier on in their careers—going further up that individual contributor track doesn't just mean getting more intense technically. It often means you've got to focus on things more like leadership, like being a bit more strategic, aligning technical initiatives with strategic goals. STEPHANIE: Yeah, and having a bigger impact and being a force multiplier, even in both the manager and, like, the staff plus role, like, that, you know, is the thing that ties the rising level. JOËL: Yeah, in many ways, maybe the individual contributor track is slightly misnamed because while, yes, you're not managing a sort of sub-organization within the company, it's still about being a force multiplier. STEPHANIE: Yeah, that's a really great point [laughs]. Maybe we'll be able to come up with a better [laughs] name for that. JOËL: I've mentioned several times on this podcast that I've been enjoying playing Dungeons & Dragons, D&D, with some friends and some colleagues. And something that was particularly fun that some friends and I did this summer is we hired a professional DM to run one shot for us. And that was just an absolutely lovely experience. Well, as a result of that, I am now subscribed to this guy's newsletter. And he'll do, like, various D&D events at different times. One thing that was really cool that I found out recently...as we're recording this, it's the week before election day in the U.S. And because a lot of voting happens in schools, typically, schools have the day off. And so, this guy sent out an email saying he was offering to run a, like, all day...effectively, a little mini-D&D camp for school-age kids on election day so that you can do your work. You can go vote, and you don't have to...basically, he'll watch your kids for you and, like, get them introduced to playing D&D, which I think is just a really cool thing to do. STEPHANIE: I love that. It's so heartwarming [laughs]. And it's such a great idea because, oftentimes, people are still working, and so they need childcare, like, on those kinds of days. And yeah, I think D&D is such a fun thing for kids to get into, too. You know, it requires so much, like, imagination, and I can imagine it's such a blast. JOËL: I got that email, and I was like, that is such a perfect idea. I love it so much. STEPHANIE: I wanted to plug my D&D recommendation. I'm pretty sure I have mentioned it on the show before. But there is a podcast that I listen to called Not Another D&D Podcast, which is, you know, a live play Dungeons & Dragons podcast campaign that's hosted by these comedians, formerly of CollegeHumor, and it's very fun. I always laugh. They have this, like, a kind of offshoot of the main show that they do called D&D Court, which is very fun. Because, as you were saying, like, you know, you hired a DM to run your game. And I know that...I'm sure lots of people have fun stories about their home games and, like, the drama that happens [laughs] with their friends. JOËL: Absolutely. Absolutely. STEPHANIE: And so, with D&D Court, listeners can write in with their drama or their conflicts and get an official ruling from the hosts about who was right [laughs] in the situation that they write in about. JOËL: So, you get to bring your best rules lawyering to the D&D Court. STEPHANIE: Yeah, exactly [laughs]. JOËL: That sounds kind of amazing. Recently, I had someone reach out to me asking about an older blog post that we'd written about the Sandi Metz Rules. This blog post was initially published in 2013, so ten years ago, and was talking about some guidelines that Sandi Metz at the time was talking about that she was using in some of her code. And we talked about how our experience was applying those to some of our work as well. And so, the question was, you know, ten years later, is that still something that thoughtbot developers like to follow in their code? We'll link to the article in the show notes. But I'll just read out the rules here real quick. So, there's four of them. The first one is a class can be no longer than 100 lines of code. The second is a method can be no longer than five lines of code. The third is pass no more than four parameters into a method, and hash options count, so no getting clever with those. And then, finally, controllers can only instantiate one object. You only get one instance variable. And views can only talk to that one instance variable. Had you or are you familiar with these rules? Is that something that you think about or use in your daily writing of code? STEPHANIE: Yeah. So, when you proposed this topic, I had to revisit these rules. And I can't recall if I had seen them before. They seemed familiar. And I've read, you know, a couple of Sandi Metz's books, so maybe those were places where she had mentioned them. But the one thing that really struck me when I was first reading the rules was how declarative they were in terms of, like, kind of just telling you what the results should be without really saying how. So, for example, the one where you said, you know, a method should not be more than five lines [laughs], I had the silly thought of, like, well, you could just, you know, stuff everything into a single line [laughs] and just completely disregard line limit if you wanted, and it would technically still follow the rule. JOËL: If they didn't want us to do that, they wouldn't give us semicolons in Ruby. STEPHANIE: Exactly [laughs]. So, that is kind of what struck me at first. Is that something you noticed? JOËL: I think what is interesting with them is that there's not always a ton of rationale given behind them. Our article talks a little bit about some of the why that might be helpful and how that might look like in practice. I'm not sure what Sandi's original...I don't know if it was one of her books or maybe on a...it might have been on a podcast appearance she talked about them, so she might go more in-depth there. But yeah, they are a little bit declarative. It's just like, hey, here's...it's almost basically the kind of thing that can be enforced by a linter, which is perhaps the point. STEPHANIE: Ooh, that's really interesting. It's like, on one hand, I like how simple they are, right? It's like, they're very obvious. If you're not following them, you can tell. But on the other hand, they seem to be more of a supplement to the gained knowledge and experience that you kind of get from knowing how to implement those rules. I think you and I will both agree that we don't want to stuff everything [laughs] into a single line with semicolons. But if someone who maybe is newer to development and is coming to these rules, I think they might be wondering, like, how do I do this? JOËL: Do you follow these rules in your own code? STEPHANIE: I think the ones that are easier to follow, for me, and that I think I've come to do more instinctually, are the rules about class line length and method line length just because I'm kind of looking out for opportunities to pull out a method or, you know, make sure that this class is just doing one thing. And if it's starting to seem to cover a couple of different responsibilities, I'm a little bit more on the lookout. But I do like these rules as like, you know, like, hey, once you hit, you know, 100 lines in a class, like, maybe that's your cue to start thinking about opportunities for extraction. JOËL: Do you sort of consciously follow these rules or have them maybe even encoded in a linter? Or is it more you're following other things, and somehow, it just lines up with these principles? STEPHANIE: I would say that, like, I'm not thinking about them very actively. But that could be a very interesting exercise, and I think, you know, that's what folks did in the blog post. They were like, hey, we took these rules, and we really kept them in mind as we were developing. But I think kind of what we were talking about earlier about, like, what we've learned or the strategies we've learned to implement kind of converge on these rules. And the rules actually are more of the result of other ideas or heuristics that we follow. JOËL: I mean, you dropped the keyword heuristics there. And I think that brings me back to an earlier episode we did where we talked about heuristics. And one of the things that came up on that episode was the idea that, oftentimes, we use heuristics as a way to sort of flatten a lot of experience and knowledge into sort of one, like, short rule, or short phrase, or something, one guideline, even though it's sort of trying to just summarize a mountain of wisdom. And so, oftentimes, you can look at something like these rules and be like, okay, well, what's the point? Or maybe you even just follow it to the letter without really thinking about the why behind it, and that can sometimes be problematic. And on the other hand, you might know all of the ideas that go behind them. And without necessarily knowing the rule itself, you just kind of happen to follow it because you're intimately familiar with all of these other software principles that converge on those same ideas. STEPHANIE: Yeah, agreed. I think that the more interesting ones to me are the no more than four method arguments and only one instance variable per controller. JOËL: Interesting. STEPHANIE: I'm curious if those are sparking anything for you [laughs]. JOËL: I think the no more than four method arguments, to me, is probably the least controversial. It's generally accepted that having many arguments to a method is a code smell. And there's a few different code smells that are related to that. There's forms of coupling incandescence; there are data clumps, things like that. I've often heard a sort of rule of three. And so, if you're going more than three, then you might want to revisit the structure of what you're building. Four is a bit of an arbitrary cut-off, I'll agree. Most of these are arbitrary cut-offs. But I think the idea to maybe keep your method to fewer arguments is generally a good thing to do. STEPHANIE: I liked that the rule points out that hash options account because I think that's maybe where people get a little more hand-wavy, or you have your ops hash [laughs] that can be just a catch-all for anything. You know, it's like, once you start putting stuff in there, I don't know, I feel like it's a like a law of the universe. It's like, oh, people will just stuff more things in there [laughs]. And it takes obviously more effort or, like, specific energy to, like, think through what those things might represent, or some alternative ways of handling those arguments. We definitely do have, I think, a couple of episodes on value objects. But that's something that we have talked a lot about before in terms of, you know, how can we take some kind of primitive data, hashes included, and turn them into a richer object that can then be passed on its own? JOËL: Right. And an options hash is generally...it's too much of a catch-all to really have an identity as its own sort of value object. It doesn't really represent any single thing. It's just everything else bag of data. One thing that's interesting that the article notes is that a lot of the helpers in Rails take a lot of arguments and that it is absolutely not worth trying to fight the framework to try to follow these rules. So, the article does take a very pragmatic approach, I think, to the idea of these rules. STEPHANIE: Yeah. And I think there is even a caveat to the rules where it's like, you can break them if you have a good reason, or if you're working with someone else and they give you the thumbs up [laughs], which I really like a lot because it almost kind of compels you to stop and be like, do I have a good reason of doing this? Just making sure, or I'll run it by a friend. And shifting that, I guess, that focus from kind of just coding from, like, your default mode of thinking to a more active one. JOËL: Right. There is a rule zero, which says you can break any of the other rules as long as you convince either your pair or your reviewer to give you a thumbs up on breaking the rule. So, you'd mentioned the fourth rule about a single instance variable in a controller kind of was one of the ones that stood out to you. What is particularly striking about that rule? STEPHANIE: I think this one is hard to follow, and I think the blog post mentions that as well. Because at least I've seen our web applications grow more and more complex. And it can be really challenging to just be like, what is this page doing? Like, what, you know, data does it need to know? And have that be the single thing. Because really, a lot of our web apps have a lot of things [laughs] that they're doing, and sometimes it feels like you have to capture more than one object or at least, like, a responsibility in this way. I think that's the one that I, you know, in my ideal world, I'm like, yeah, like, we have all these, like, perfectly RESTful routes. And, you know, we're only dealing with, you know, a single resource. But once you start to have some more complexity, I think that can be a little more challenging. JOËL: I think it's interesting that you mentioned RESTful routing because I think that is maybe one of the bigger things that does trigger having more instance variables in your controller actions. If you're following sort of the traditional Rails RESTful routes, every page is generally focused on a singular resource. Now, that may not necessarily line up with a table in your database, and that's fine. But you're dealing with a singular thing or perhaps, you know, in the case of an index page, a singular collection of things, which can be represented with a single instance variable. Once you start adding custom routes that may not be necessarily tied to a particular resource, now you can very easily kind of have a proliferation of all sorts of different things that interact with each other because you're no longer centered on a single thing. STEPHANIE: Yeah, that's true, which actually reminds me of something we've talked about before, too, when we were both reading Sustainable Rails. The author talks about custom routes and actually advocates for making all routes RESTful. And if you need a vanity URL or something like that, you can always alias it. That I liked, right? It's like, okay, even if, you know, your resource is not something that's like, ActiveRecord-backed, is there some abstraction or concept of a resource in there? And I actually did really like in the blog post in the example; that is one that I've used before, too. They were dealing with this idea of a dashboard, which I would, you know, say is pretty common in a lot of web applications these days. And it's funny because a dashboard can hold so much data, right? It's really, like, a composite of a lot of different things, you know, what is most, like, useful for the user to see in one place. But they were in the blog post. And this, again, this is kind of something that I've done before. They were able to capture that with the idea of, like, a dashboard as an object and that being codified using a presenter or a facade. JOËL: Right. So, instead of having a group, and a status, and a user, and all these, like, separate things that your page that you're showing is a sort of collection of all these different types of objects, you wrap them together in a dashboard object that's kind of a facade. And I guess that really does line up with the idea of RESTful routing because you're likely going to have a dashboard's controller show action that's showing the user's dashboard. So, it makes sense, you know, that show page is rendering a dashboard object. STEPHANIE: Can we talk a little bit about things not to do, or maybe things that might be a little more questionable [laughs], and if you've seen them and how you felt about them? JOËL: I think it is sometimes tricky to define your boundaries right in that sometimes you create a facade object that really is just...it doesn't really represent anything. It's just there to wrap around some other things. And sometimes that can be awkward. I think the dashboard works partly because it lines up so neatly with the sort of RESTful routing and thinking in terms of resources that you want to do at the controller layer. But drawing boundaries incorrectly or just trying to throw everything in some kind of grab bag object can...it's not a magic bullet, right? You've got to put some thought into the data modeling, even when you are pulling the facade pattern. STEPHANIE: Yeah, I think other things that I've seen before that could theoretically follow this rule maybe [laughs], you know, I'd love to hear your thoughts about it. When you start, you're like, oh, like, my controller action method does just, you know, set one instance variable. But it turns out that there's all these other instance variables that either through a hook or, like, in the parent controller or even in the view I've seen before, too [laughs]. And I'm just kind of curious if that kind of raises your eyebrow at all or if you've seen any good reasons for doing so. JOËL: I think setting instance variables in a view would absolutely cause me to raise an eyebrow. STEPHANIE: [laughs] Agreed. JOËL: Generally, don't put logic in the view. I think that we definitely have in parent controllers; we'll set other instance variables for things like maybe a current user, right? That's how we store that state. And I think that is totally fine to have around. Typically, we don't access that instance variable directly. We're referencing some kind of helper method. But yeah, I would not consider that a violation of the rule. I think another common one that might come up is when you have some kind of nested resource. And so, in your URL, you might have a nested resource where you're saying, "Oh, I'm looking at specifically this comment under this article or something like that." And then, you want to have access to both objects in the controller. So, I think that's a pretty common scenario where you might want to have both instance variables. Something that I'm thinking about...this is not a fully formed thought, so I'm curious about your opinions here. Is there an interesting distinction between variables in code that you want to use within a controller versus variables that you want to be accessible from a view? Because instance variables in a controller are kind of overloaded. They're a way of having state in a controller, but they're also a way of passing data into a view. And so, that sort of dual purpose there maybe causes them to be a little bit trickier to reason about than instance variables in a random Ruby object. What do you think? STEPHANIE: Yeah, I was actually having the same thought as you were going there, which is that it is kind of interesting that the view, you know, is that level of what you want to display to your user. But it can have access to, like, whatever you put in the controller [laughs], and that is...and, you know, in some ways, it's like, that connection needs to happen somewhere, right? And it's here. But I think that can definitely be abused sometimes, too. So, this, you know, fourth rule that we're talking about really has to do with a more traditional Rails app. But, again, with the complexity of web apps in 2023 [chuckles], you know, we also see Rails used just as an API a lot with a separate front-end framework. And your controller is rendering some JSON, which I think has that harder boundary between what is the data that the server is involved with and what we want to send to our client. And I'm curious if you have any thoughts about how this rule applies in that situation. JOËL: I think I tend to see not really any difference there. If I'm building an API, typically, I'm trying to do so in a pretty RESTful manner. Maybe I'm doing a GraphQL API, and things might be different for that. But for a traditional REST API, yeah, typically, you're fetching one resource or some sort of compound resource, in which case, you're representing that with a facade object. And yep, you can generally get away, I think, with a single instance variable with, you know, a few exceptions around maybe some extra context about maybe something like the current user, or a parent object, or something like that. I guess the view is really you're using a different mechanism for rendering JSON, and there are a bunch out there that the community uses. I think I don't really see a difference between rendering to HTML versus rendering to JSON, or XML, or whatever. How about you? STEPHANIE: That's a good point. I think I'm with you where the rule still applies. But I have also seen things get really loosey-goosey [laughs] when we decide we're rendering JSON, and now we're suddenly putting the instance variables into a hash along with other stuff. But what you said was interesting about, like, sometimes you do need that extra context, right? And, like, figuring out what the best way to package that requires a bit of, like, sustained thought, I think, because it can, you know, be really easy to be like, oh well, this is the one interface that I have to get data from the server. So, if I just sneak this in here [laughs], what's the matter? But yeah, I think, you know, that's probably why rules like this exist [laughs] to help provide some guardrails and make us think a little deeper about it. JOËL: I think sometimes, as a community, we maybe exaggerate the differences between, like, RESTful HTML view and a RESTful JSON API. I tend to think of them as more or less the same. We just have, you know, a different representation the V layer of our MVC framework. Everything else still kind of lines up. STEPHANIE: Yeah, that's a really good point. I actually hadn't thought about it that way. Because I think maybe I have been influenced by the world of GraphQL [laughs] a little bit, or it's kind of hard to have a foot in both worlds, where you maybe have to context switch a little bit about, like, the paradigms, and then you find them influencing you in different ways. Because I have seen sometimes, like, what maybe initially were meant to be traditional more, like, RESTful JSON APIs kind of start to turn into that, like, how do we get what we need from this endpoint? JOËL: I'm curious how you feel in general about the facade pattern. Is that something that you've used, something that you like? STEPHANIE: I think I would say that I don't actually reach for it, like, upfront, right? Usually, I'm still trying to maybe put some things in my models [laughs]. But I have used it before once; it kind of became clear that, like, a lot of the methods on the model had to do with more really server-side concerns. And I was, like, wanting to just pull out some presentational pieces. I think the hardest part with the facade pattern is naming. I have really struggled sometimes to think of, like, it's not quite the component that makes it up. So, what is it instead? JOËL: Right. Right. I think, for me, sometimes the naming goes the other way around in that I'll start more to kind of, like, routing our resource level and try to think about, okay, this particular view of the data that I want to have, or this particular operation that I want to do, what am I actually dealing with? What is the resource here? So, maybe I'm viewing a dashboard. Or maybe what I'm doing is creating or destroying a subscription, even though those are not necessarily tables in the database. And once I have that underlying concept, then I can start creating an object that represents that, which might be a combination of multiple ActiveRecord models that represent tables. STEPHANIE: Yeah. You're actually pointing out, like, a really great use case that we see a lot, I think, is when you start to have to reach for resources, you know, that are different ActiveRecord classes. And how do you combine them together to represent the idea that you want, you know, for your feature? JOËL: I think it's more of, like, an outside-facing perspective rather than an inside-facing perspective. So, instead of looking at, hey, these are the set of ActiveRecord classes I have because these are my database tables, how can I, like, tack on to them to make this operation work? I'll sort of start almost from, like, a zoomed-out perspective, blank slate to say, "Hey, this is the kind of operation that I'm trying to do. What sort of resource am I dealing with ideally?" And, you know, maybe the idea is, okay, I'm dealing with a dashboard. I'm trying to subscribe to something...a newsletter, so the idea is I'm creating a subscription. Then, from there, I can start looking at, okay, do I have the concept of a subscription in this application? Oh, I don't. There is no subscriptions table because that's not a thing that we track in our data mode. That's fine. But I probably need at least some kind of in-memory object to track the idea of a subscription, and then maybe from there, that grows. So, I'm kind of working from the problem towards the database rather than from the database out. STEPHANIE: Yeah, I like that a lot. The outside-in phrase that you used really triggered something for me, which is being product engineers, right? Like, having a seat at the table when the feature is in that, like, ideation phase, I think is also really important because that's where you really learn what that like, abstraction is at the user level. And also, it could be a really good place to give your input if the feature is being designed in a way that doesn't really support the, you know, kind of quality of code and, like, separation that you would like. That's the part that I'm still working on and still learning how to do. But sometimes, you know, it's, like, really critical to the job to, like, be in that room and be like, these designs; what are some places that we could extract it at that level even? And kind of, like, separate things out from there rather than having to deal with it [laughs] deep in your codebase. JOËL: I think what I'm really kind of hearing and emphasizing in what you just said is the importance of not just writing code but being involved in the product and how that really enriches you because you know the problem domain. And that allows you to then write the code that you need at the different levels of the app to best model the situation you're working with. So, we've kind of gone through all the rules and talked about them. I'm curious, though, for you, are these rules that you follow in your code? How closely do you adhere to this set of rules? Is this still something that's relevant to you in 2023 as much as it was to the authors of that blog post in 2013? STEPHANIE: I have to say they're not ones that I have thought about on a daily basis, but after this conversation, maybe they will be. And I am kind of excited to maybe, like, bring this up to other people on my team and be like, "What do you think about these rules?" Just, like, revisiting them as a group or just, like, having that conversation. Because I think that's, you know, where I am most interested in is, like, is wondering how other people incorporate them into their work and hearing different opinions from the team. And I think there's a lot of, like, generative discussion that ultimately leads to better code as a result. JOËL: I think for myself, I'm not following the rules directly. But a lot of my code ends up approximating those rules anyway because of other principles that I follow. So, in practice, while my code doesn't strictly follow those rules, it does look pretty close to that anyway. STEPHANIE: I almost think this could be a great, you know, discussion for your team, too, like, if any listeners want to...not quite a book club but kind of an article club, if you will [laughs], and see how other people on your team feel about it. Because I think that's kind of where there is, like, a really sweet spot in terms of learning and development. JOËL: On that note, shall we wrap up? STEPHANIE: Let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeee!!!!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at tbot.io/referral. Or you can email us at referrals@thoughtbot.com with any questions.
Joël was selected to speak at RubyConf in San Diego! After spending a month testing out living in Upstate New York, Stephanie is back in Chicago. Stephanie reflects on a recent experience where she had to provide an estimate for a project, even though she didn't have enough information to do so accurately. In this episode, Stephanie and Joël explore the challenges of providing estimates, the importance of acknowledging uncertainty, and the need for clear communication and transparency when dealing with project timelines and scope. RubyConf 2023 (https://rubyconf.org/) How to estimate well (https://thoughtbot.com/blog/how-to-estimate-feature-development-time-maybe-don-t) XKCD hard problems (https://xkcd.com/1425/) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: Big piece of news in my world: I recently got accepted to speak at RubyConf in San Diego next month in November. I'm really excited. I'm going to be talking about the concept of time and how that's actually multiple different things and the types of interactions that do and do not make sense when working with time. STEPHANIE: Yay. That's so exciting. Congratulations. I am very excited about this topic. I'm wondering, is this something that you've been thinking about doing for a while now, or was it just an idea that was sparked recently? JOËL: It's definitely a topic I've been thinking about for a long time. STEPHANIE: Time? [laughs] JOËL: Haha. STEPHANIE: Sorry, that was an easy one [laughs]. JOËL: The idea that we often use the English word time to refer to a bunch of, like, fundamentally different quantities and that, oftentimes, that can sort of blur into one another. So, the idea that a particular point in time might be different from a duration, might be different from a time of day, might be different to various other quantities that we refer to generically as time is something that's been in the back of my mind for quite a while. But I think turning that into a conference talk was a more recent idea. STEPHANIE: Yeah, I'm curious, I guess, like, what was it that made you feel like, oh, like, this would be beneficial for other people? Did everything just come together, and you're like, oh, I finally have figured out time [laughs]; now I have this very clear mental model of it that I want to share with the world? JOËL: I think it was sparked by a conversation I had with another member of the thoughtbot team. And it was just one of those where it's like, hey, I just had this really interesting conversation pulling on this idea that's been in the back of my mind for years. You know, it's conference season, and why not make that into a talk proposal? As often, you know, the best talk proposals are, at least for me, I don't always think ahead of time, oh, this would be a great topic. But then, all of a sudden, it comes up in a conversation with a colleague or a client, or it becomes really relevant in some work that I'm doing. It happens to be conference season, and like, oh, that's something I want to talk about now. STEPHANIE: Yeah, I like that a lot. I was just thinking about something I read recently. It was about creativity and art and how long a piece of work takes. And someone basically said it really just takes your whole life sometimes, right? It's like all of your experiences accumulated together that becomes whatever the body of work is. Like, all of that time spent maybe turning the idea in your head or just kind of, like, sitting with it or having those conversations, all the bugs you've probably encountered [laughs] involving date times, and all of that coalescing into something you want to create. JOËL: And you build this sort of big web of ideas, not all that makes sense to talk about in a conference talk. So, one of the classic sources of bugs when dealing with time are time zone and daylight savings. I've chosen not to include those as part of this talk. I think other people have talked about them. I think it's less interesting or less connected to the core idea that I have that, like, there are different types of time. Let's dig into what that means for us. So, I purposefully left that out. But there's definitely a lot that could be said for those. STEPHANIE: Awesome. Well, I really look forward to watching your talk when it is released to the public. JOËL: So, our listeners won't be able to tell, but we're on a video call right now. And I can see from your background that you are back at home in Chicago. It's been a few weeks since we've recorded together. And, in the last episode we did, you were trying out living somewhere in Upstate New York. How was that experience? And what has the transition back to Chicago been for you? STEPHANIE: Yeah, thanks for asking. I was in Upstate New York for the whole month of September. And then I took the last two weeks off of work to, you know, just really enjoy being there and make sure I got to do everything that I wanted to do out there before I came home to, you know, figure out, like, is this a place where I want to move? And yeah, this is my first, like, real full week back at work, back at home. And I have to say it's kind of bittersweet. I think we really enjoyed our time out there, my partner and I. And coming back home, especially, you know, when you're in a stage of life where you're wanting to make a change, it can be a little tough to be like, uh, okay, like, now I have to go back [laughs] to what my life was like before. But we've been very intentional about trying to bring back some of the things that we enjoyed being out there, like, back into just our regular day-to-day lives. So, over the weekend, we were making sure that we wanted to spend some time in nature because that's something that we were able to do a lot of during our time in New York. And, yeah, I think just bringing a bit of that, like, vacation energy into day-to-day life so the grind of kind of work doesn't become too much. JOËL: Anything in particular that you've tried to bring back from that experience to your daily life in Chicago? STEPHANIE: Yeah. I think, you know, when you're in a new place, everything is very exciting and, like, novel. Before work or, like, during my breaks, I would go out into the world and take a little walk and, like, look at the houses on the street that I was staying at. Or there's just a sense of wonder, I suppose, where everywhere you look, you're like, oh, like, this is all new. And I felt very, like, present when I was doing that. And over time, when you've been somewhere for a long time, you lose a little bit of that sense of, like, willingness to be open to new things, or just, like, yeah, that sense of like, oh, like, curiosity, because you feel like you know somewhere and, like, you kind of start to expect oh, like, this street will be exactly like how I've walked a million times [laughs]. But trying to look around a little more, right? Like, be a little aware and be like, oh, like, Halloween is coming around the corner. And so, enjoying that as, like, the thing that I notice around me, even if I am still on the same block, you know, in my same neighborhood, and, yeah, wanting to really appreciate, like, my time here before we leave. Like, I don't want to just spend it kind of waiting for the next thing to happen. Because I'm sure there will also be a time where I miss [laughs] Chicago here once we do decide to move. JOËL: I don't know about you, but I feel like a sense of change, even if it is cyclical, is really helpful for me to kind of maintain a little bit of that wonder, even though I've lived in one place for a decade. So, I live in New England in the Northeast U.S. We have pretty marked seasons that change. And so, seeing that happen, you know, kind of a warm summer, and now we're transitioning into fall, and the weather is getting colder. The trees are turning all these colors. So, there's always kind of within, like, a few weeks or a few months something to look forward to, something that's changing. Life never feels stagnant, even though it is cyclical. And I don't know if that's been a similar experience for you. STEPHANIE: Yeah, I like that a lot because I think one of the issues around feeling kind of stuck here in Chicago was that things were starting to feel stagnant, right? Like, we're wanting to make a big change in our life. That's still on the table, and that's still our plan. But noticing change, even when you think like, ugh, like, this again? [laughs] I think that could really shift your perspective a little bit or at least change how you feel about being somewhere. And that's definitely what I'm trying to do, kind of even when I am in a place of, like, waiting to figure out what the next step is. Speaking of change, I had a recent lesson learned or, I suppose, a story to share with you about a new insight or perspective I had about how I show up at work that I'd like to share. JOËL: What is this new perspective? STEPHANIE: Well, I guess, [chuckles], first of all, I'm curious to get your reaction on this. Have you ever heard anyone tell you estimates are lies? JOËL: Yes, a lot. It's maybe cynical, but there are a lot of cynics in our industry. STEPHANIE: That's true. Part of this story is me giving an estimate that was a lie. So, in some ways, there is a grain of truth to it [laughs]. But I wanted to share with you this experience I had a few weeks ago where I was in kind of a like, project status update meeting. And I was coming to this meeting for the first time actually. And so, it was with a group of people who I hadn't really met before. It was kind of a large meeting. So, there were a handful of people that I wasn't super familiar with. And I was coming in to share with this bigger group, like, how the work I had been doing was going. And during that time, we had gotten some new information that was kind of making us reassess a few things about the work, trying to figure out, like, where to go next and how to meet our ultimate goal for delivering this feature. With that new information in mind, one of the project managers was asking me how long I thought it might take. And I did not have enough information to feel particularly confident about an answer, you know, I just didn't know. And I mentioned that this was kind of my first time in this meeting. There were a lot of people I didn't know, including the person who was asking the question. And they were saying, "Oh, well, you can just guess or, like, you know, it doesn't have to be perfect. But could you give us a date?" And I felt really hard-pressed to give them an answer in that moment because, you know, I kind of was stalling a little bit. And there was still this, like, air of expectancy. I eventually, I have to say, I made something up [laughs]. I was like, "Well, I don't know, like, three weeks," you know, just really pulling it out of thin air. And, you know, that's what they put down on the spreadsheet, and then they moved on [laughs] to the next item. And then, I sat there in the rest of the meeting. And afterwards, I felt really bad. I, like, really regretted it, I think, because I knew that the answer I gave was mostly BS, right? Like, I can't even say how I came up with that. Just that I, like, wanted to maybe give us some extra time, in case the task ends up being complicated, or, you know, there are all these unknowns. But yeah, it really didn't feel good. JOËL: I'm curious why that felt bad. Was it the uncertainty around that number or the fact that the number maybe you felt like you'd given, like, a ridiculously large number? Typically, I feel like when estimates are for a story, it's, like, in the order of a few days, not a few weeks. Or is it something else, the fact that you felt like you made it up? STEPHANIE: I think both, where it was such a big task. The larger and higher level the task is, the harder it is to come up with an answer, let alone an accurate one. But it was knowing that, like, I didn't have the information. And even though I was doing as they asked of me [chuckles], it was almost like I lost a little bit of my own integrity, right? In terms of kind of based on my experience doing software development, like, I know when I don't know, and I wasn't able to say it. At least in that moment, didn't feel comfortable saying it. JOËL: Because they're not taking no for an answer. STEPHANIE: Yeah, yeah, or at least that was my interpretation of the conversation. But the insight or the learning that I took away from it was that I actually don't want to feel that way again [laughs], that I don't want to give a lie as an estimate because it didn't feel good for me. And the experience that I have knowing that I don't have an answer now, but there are, like, ways to get the answer, right? What I wish I had said in that meeting was that I didn't know, but I could find out, or, like, I would let them know as soon as I did have more information. Or, like, here is the information that I do need to come up with something that is more useful to them, honestly, and could make it, like, a win for all of us. But yeah, I've been reflecting on [chuckles] that a lot. Because, in a sense, like, I really needed to trust myself and, like, trust my gut to have been able to do my best work. JOËL: I wonder if there's maybe also a sense in which, you know, generally, you're a very kind of earnest person. And maybe by giving a ridiculous number there just to, like, check a box, maybe felt like you gave way to a certain level of cynicism that wasn't, like, true to who you are as a person. STEPHANIE: Yeah, yeah, that feels real [laughs]. JOËL: Have you ever done estimation sessions where you put error bars on your number? So, you say, hey, this is my estimate, but plus or minus. And, like, the more uncertainty there is around a number, the larger those plus or minus values are to the point where I could imagine something as ridiculous as like, oh, this is going to take three weeks, plus or minus three weeks. STEPHANIE: I like that. That's funny. No, I have not ever done that before or even heard of that. That is a really interesting technique because that seems just more real to me, where, again, people have different opinions about estimation and how effective or useful it is. But for organizations where, like, it is somewhat valuable, or it is just part of the process, I like the idea of at least acknowledging the uncertainty or the ambiguity or, like, the level of confidence, right? That seems like an important piece of context to that information. JOËL: And that can probably lead to some really interesting conversations as well because just getting a big number by itself, you might have a pretty high certainty. I mean, three weeks is big enough that you might say, okay, there's definitely going to be some fuzziness around that. But getting a sense of the certainty can, in certain contexts, I find, drive really interesting conversations about why things are uncertain. And then, that can lead to some really good conversations around scoping about, okay, so we have this larger story. What are the elements of it that are uncertain that you might even talk in terms of risk? What are the risky elements of this story or maybe even a project? And how do we de-risk those? Is there a way that we could remove maybe a small part of the story and then, all of a sudden, those error bars of plus or minus three weeks drop down to plus or minus three days? Because that might be possible by having that conversation. STEPHANIE: Yeah, I like what you said about scope because the way that it was presented as this really big chunk of work that was very critical to this deadline, there was no room to do scope, right? Because we weren't even talking about what makes up this feature task. We hadn't really broken it down. In some ways, I think it was very, like, wishful, right? To be like, oh yeah, we want this feature. We're not going to talk too much about, like, the specific details [laughs], as opposed to the idea of it, right? And that, I think, is, you know, was part of what led to that ambiguity of, like, I can't even begin to estimate this because, like, it could mean so many different things. JOËL: Right. And software problems, often, a slight change in the scope can make a massive change in complexity. I always think of a classic xkcd comic where two people are talking about a task, and somebody starts by describing something that kind of sounds complex. But the person implementing it is like, "Oh yeah, no, that's, you know, it's super easy. I can do that in half a day." And then, like, the person making the ask is like, "Oh, and, by the way, one small detail," and they add, like, one small thing that seems inconsequential, and the person is just like, "Okay, sorry, I'm going to need a research team and a couple of PhDs. And it's going to take us five years." STEPHANIE: That's really funny. I haven't seen this comic before, but I need to [laughs] because I feel that so much where it's like, you just have different expectations about how long things will take. And I think maybe that is where, like, I felt really disappointed afterwards. Because in my inability to, like, just really speak up and say, like, "In my experience, like, this is kind of what happens when we don't have this information or when we aren't sure," yeah, I just wasn't able to bring that to the table in that, you know, meeting. And I really am glad we're having this conversation now because I've been thinking about, like, okay, when I find myself in this position again, how would I like to respond differently? And even just that comic feels really validating [laughs] in terms of like, oh yeah, like, other people have experienced this before, where when we don't have that shared understanding or, like, if we're not being super transparent about how long does a thing really take, and why does it make it complex, or, like, what is challenging about it, it can be, like, speaking in [chuckles] two different languages sometimes. JOËL: I think what I'm hearing almost is that in a situation like what you found yourself in, you're almost sort of wishing that you'd picked one extreme or the other, either sort of, like, standing up to—I assume this is a project manager or someone...to say, "Look, there's no number I can give you that's going to make sense. I'm not going to play this game. I have no number I can give you," and kind of ending it there. Or, on the other hand, leaning into, say, "Okay, let's have a nuanced conversation, and we'll try to understand this. And we'll try to maybe scope it and maybe put some error bars on this or something and try to come up with a number that's a little bit more realistic." But by kind of, like, trying to maybe do a middle path where you just kind of give a ridiculously large number that's meaningless, maybe everybody feels unfulfilled, and that feels, like, maybe the worst of the paths you could have taken. STEPHANIE: Yeah, I agree. I like that everyone [laughs] feels slightly unfulfilled point. Because, you know, my estimate is likely wrong. And, like, what impact will that have on other folks and, you know, their work? While you were saying, like, oh yeah, here were the kind of two different options I could have chosen, I was thinking about the idea of, like, yeah, like, there are different strategies depending on the audience and depending who you're working with. And that is something I want to keep in mind, too, of, like, is this the right group to even have the, like, okay, let's figure this out conversation? Because it's not always the case, right? And sometimes you do need to just really stand firm and say, like, "I can't give you an answer. And I will go and find the people [laughs] who I can work this out with so that I can come back with what you need." JOËL: And sometimes there may be a place for some sort of, like, placeholder data that is obviously wrong, but you need to put a value there, as long as everybody's clear on that's more or less what's happening. I had to do something kind of like that today. I'm connecting with a third-party SAML for authentication using the service Auth0. And this third party I'm talking to...so there's data that they need from me, and there's data that I need from them. They're not going to give me data until I give them our data first, so this is, like, you know, callback URLs, and entity IDs, and things like that you need to pass. In order to have those, I need to stand up a SAML connection on the Auth0 side of things. In order to create that, Auth0 has a bunch of required fields, including some of the data that the third party would have given me. So, we've got a weird thing where, like, I need to give them data so they can stand up their end. But I can't really stand up my end until they give me some data. STEPHANIE: Sounds like a circular dependency, if I've ever heard one [laughs]. JOËL: It kind of is, right? And so, I wanted to get this rolling. I put in a bunch of fake values for these callback URLs and things like that in the places where it would not affect the data that I'm giving to the third party. And so, it will generate as a metadata file that gets generated and stuff like that. And so, I was able to get that data and send it over. But I did have to put a callback URL whose domain may or may not be example.com. STEPHANIE: [laughs] Right. JOËL: So, it is a placeholder. I have to remember to go and change it later on. But that was a situation where I felt better about doing that than about asking the third party, "Hey, can I get your information first?" STEPHANIE: Yeah, I like that as sometimes, like, you recognize that in order to move forward, you need to put something or fill in that gap. And I think that, you know, there was always an opportunity afterwards to fix it or, like, to reassess and revisit it. JOËL: With the caveat that, in software, there's nothing quite so permanent as a temporary fix. STEPHANIE: Oof, yeah [laughs]. That's real. JOËL: So, you know, caution advised, but yes. Don't always feel bad about placeholders if it allows you to unblock yourself. STEPHANIE: So, I'm really glad I got to bring up this topic and tell you this story because it really got me thinking about what estimates mean to me. I'm curious if any of our listeners if you all have any input. Do you love estimates? Do you hate them? Did our conversation make you think about them differently? Feel free to write to us at hosts@bikeshed.fm. JOËL: On that note, shall we wrap up? STEPHANIE: Let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeeeeeeee!!!!! AD: Did you know thoughtbot has a referral program? If you introduce us to someone looking for a design or development partner, we will compensate you if they decide to work with us. More info on our website at tbot.io/referral. Or you can email us at referrals@thoughtbot.com with any questions.
Stephanie is engrossed in Kent Beck's Substack newsletter, which she appreciates for its "working thoughts" format. Unlike traditional media that undergo rigorous editing, Kent's content is more of a work-in-progress, focusing on thought processes and evolving ideas. Joël has been putting a lot of thought into various tools and techniques and realized that they all fall under one umbrella term: analysis. From there, Stephanie and Joël discuss all the productivity tricks they like to use in their daily workflows. Do you have some keyboard shortcuts you like? Are you an Alfred wizard? What are some tools or mindsets around productivity that make YOUR life better? Kent Beck's Substack Tidy First? (https://tidyfirst.substack.com/) Debugging: Listing Your Assumptions (https://thoughtbot.com/blog/debugging-listing-your-assumptions) Dash (https://kapeli.com/dash) Alfred (https://www.alfredapp.com/) Rectangle (https://rectangleapp.com/) Meeter (https://apps.apple.com/us/app/meeter-for-zoom-teams-co/id1510445899) Vim plugins (https://github.com/thoughtbot/dotfiles/blob/main/vimrc.bundles#L32-L50) from thoughtbot's dotfiles, including vim-projectionist () for alternate files Go To Spec VS Code plugin (https://marketplace.visualstudio.com/items?itemName=Lourenci.go-to-spec) Feedbin (https://feedbin.com/) Energy Makes Time by Mandy Brown (https://everythingchanges.us/blog/energy-makes-time/) Transcript: AD: Ruby developers, The Rocky Mountain Ruby Conference returns to Boulder, Colorado, on October 5th and 6th. Join us for two days of insightful talks from experienced Ruby developers and plenty of opportunities to connect with your Ruby community. But that's not all. Nestled on the edge of the breathtaking Rocky Mountains, Boulder is a haven for outdoor lovers of all stripes. Take a break from coding. Come learn and enjoy at the conference and explore the charm of Downtown Boulder: eclectic shops, first-class restaurants and bars, and incredible street art everywhere. Immerse yourself in the vibrant culture and the many microbrew pubs that Boulder has to offer. Grab your tickets now at rockymtnruby.dev and be a part of the 2023 Rocky Mountain Ruby Conference. That's rockymtnruby.dev, October 5th and 6th in Boulder. See you there. JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. STEPHANIE: And I'm Stephanie Minn. And together, we're here to share a bit of what we've learned along the way. JOËL: So, Stephanie, what's new in your world? STEPHANIE: So, I have a new piece of content that I'm consuming lately. That is Kent Beck's Substack [chuckles], Kent Beck of Agile Manifesto and Extreme Programming notoriety. I have been really enjoying this trend of independent content creation in the newsletter format lately, and I subscribe to a lot of newsletters for things outside of work as well. I've been using an RSS feed to like, keep track of all of the dispatches I'm following in that way so that it also kind of keeps out of my inbox. And it's purely just for when I'm in an internet-reading kind of mood. But I subscribed to Kent's Substack. Most of his content is behind a subscription. And I've been really enjoying it because he treats it as a place for a lot of his working thoughts, kind of a space that he uses to explore topics that could be whole books. But he is still in the phase of kind of, like, thinking them through and, like, integrating, you know, different things he's learning, and acknowledging that, like, yeah, like, not all of these ideas are fully fleshed, but they are still worth publishing for people who might be interested in kind of his thought process or where his head is at. And I think that is really cool and very different from just, like, other types of content I consume, where there has been, like, a lot of, especially more traditional media, where there has been, like, more editing involved and a lot of time and effort to reach a final product. And I'm curious about this, like I mentioned, trend towards a little less polished and people just publishing things as they're working through them and acknowledging that the way they're thinking about things can change over time. JOËL: It sounds like this is kind of halfway between a book which has gone through a lot of editing and, you know, a tweet thread, which is pure stream of consciousness. STEPHANIE: Yeah, that's a really great insight, actually. And I think that might be my sweet spot in terms of things I enjoy consuming or reading because I like that room for change and that there is a bit of a, you know, community aspect to Substack where you can comment on posts. But, at least in my experience, has seemed, like, relatively healthy because it is, you know, you're kind of with a community of people who are at least invested or willing to pay [chuckles] for the content. So, there is some amount of good faith involved. His newsletter title itself it's called "Tidy First?" And so, that almost implies that it's, like, something he's still exploring or experimenting with, which I think is really cool. It's not like a I have discovered, like, the perfect way to do things, and, you know, you must always tidy first before you do your software development. He's kind of in the position of, this is what I think works, and this is my space for continuing to refine this idea. JOËL: I'm curious: are there any sort of articles that you've read or just thoughts in general that you've seen from Kent that are particularly impactful or memorable to you? STEPHANIE: Yeah. One I read today during my investment time is called Accountability in Software Development. And it was a very interesting take on the idea of accountability, not necessarily, like, when it's forced by others or external forces like a manager or, you know, your organization, but when it comes from yourself. And he describes it as a way to feel comfortable and confident in the work that he's doing and also building trust in himself and in his work but also in his teams. By being transparent and literally accounting for the things that he's doing and sharing them, communicating them publicly, that almost ends up diminishing any kind of, like, distrust, or shame, or any of those weird kind of squishy things that can happen when you hide those things or, like, hide what you're doing. It becomes a way to foster the good parts of working with other people but not in a necessarily like, resentful way or in a hierarchical way. I was really interested in the idea of accountability, ultimately, like, for yourself, and then that ends up just propagating to the team. JOËL: That's a really interesting topic because I think it sort of sits at the intersection of the personal and the technical. STEPHANIE: Yeah, absolutely. He mentions more technical strategies or tasks that kind of do the same thing. You know, he mentions test-driven development, as well as, like, a way of holding yourself accountable to writing software that, you know, doesn't have bugs in it. So, I think that it can be applied to, you know, exactly both of those, like, interpersonal stuff and also technical aspects too, anyway, that's what's new in my world. Joël, what about you? JOËL: So, this year, I've been putting a lot of thought into a variety of tools and processes. And I think I've come to the realization that they all really fall under one kind of umbrella term, and that would be analysis. It's a common step in some definitions of the traditional software development lifecycle. And it's where you try to after you've kind of gathered the requirements, try to break them down and understand what exactly that means from a technical perspective, what needs to happen. And so, a lot of the things that have been really fascinating to me this year have been different techniques that I can use to become better at that sort of phase. STEPHANIE: Wow. That's very powerful, I think. And honestly, the first thing that comes to mind is, how do you make time for it? JOËL: I think we all do it to a certain extent. You know, you pick up a ticket, and there is a prose description of some work to be done, hopefully not telling you directly, like, just go make a change to this class, but here's a business problem to be solved. And then you have to sort of figure out how to break it down. So, this can be as simple as, oh, what objects, what classes do I need to introduce for this change? But it might be more subtle in terms of thinking, okay, well, what are the edge cases I need to think about? Where are things that could fail, and how am I going to handle failure? So, there's a variety of techniques that you can use to get better at all of these. You can use them kind of at the micro level when thinking about just a ticket. You can use them when working on a larger epic, a larger initiative, a whole project because I think analysis fits into kind of all of these levels. And so, I think those are the techniques that have been most exciting to me this year and that have really connected. STEPHANIE: That is very exciting. It's triggering a lot of thoughts for me about how I incorporate analysis into my work and how that has actually evolved; where I think before, earlier in my career, I assumed that the analysis had been done by someone else who knew better than me or who knew more than me. And that by the time that you know, a piece of work kind of landed in my lap, I was like, okay, well, I just want to know what to do, right? Like, I want someone else to tell me what to do [laughs]. But now I think I have taken it upon myself to do more of that and, like, have realized that it's part of my role. And sometimes it will now be kind of a flag or, like, a signal to me when that hasn't been done. And I can tell when I receive a ticket, and it's, like, maybe missing the business problem or doesn't have enough information. And determining whether that is information that I need to go and find out, or if there's someone else who I can work together with to do that analysis with, or having a better understanding of, like, what is within my realm of analysis to do, and what I need to encourage other people to do analysis for before the work is ready for me. JOËL: I think there is an interesting distinction between more traditional requirements gathering and analysis, where traditional requirements gathering is getting all that business problem information from product people, from customers, things like that. The analysis step is often a little bit more about breaking down a business problem into, like, what are the technical ramifications of that? But there can be a little of a synergy there where sometimes, once you start exploring the technical side of it, it might bring up a lot of edge cases that have impacts on the product side, on the business side. And then you have to go back to the businesspeople and say, "Hey, we only talked about sort of the happy path. What happens if payment is declined? What do we want to do there?" And now we're back in sort of that requirements gathering phase a little bit more rather than purely analysis. But it can come out of an analysis phase where you've done maybe some state machine diagramming to try to better understand how things flow from one phase to another. Or maybe you were building out a truth table for some complex logic and realized, wait a minute, there's an edge case I didn't handle. It's not a strictly linear process. The two kind of feed into each other and, honestly, into the implementation side as well. STEPHANIE: Yeah, I'm with you there. I'm thinking about a piece of work that I've been working on, where we were thinking of doing a database migration and adding some new columns to a table. But the more I dug into it, the more I realized that that was the first idea or the immediate idea that came from a need that I had limited information about. And what was nice was I was able to sit on it for a little bit, get some input from others. And I realized that there were all of these things that I couldn't answer yet. And someone, I think literally asked in a code review if you've already done this analysis, between knowing that these columns will be the kind of extent of what you need versus, you know, will the data end up needing more columns? And should the data model be a little more flexible to that potential change? And they said, "If you had already done this analysis, then, like, otherwise, it looks good to me." And I was like, "Oh, I didn't." [laughs] And that encouraged me to go back to some cross-functional members of the team and ask more questions. And that has taken more time. That was another challenge that I had to encounter was saying like, "Yeah, we started this, and we made some progress. But actually, we need to revisit a few things, like a few parts of the premise, before continuing on." JOËL: Are there any techniques or approaches that you particularly enjoy when it comes to doing an analysis or that maybe are go-to's for you? STEPHANIE: Reminding myself to revisit my assumptions [laughs], or at least even starting by being really clear about what I'm assuming, right? Because I think that has to happen first before you can even revisit them is having an awareness of what assumptions you're making. And I actually think this is where collaboration has been really helpful, where I've been working on this task with another developer on my team. And when we've been talking about it, I found myself saying, "Oh, I'm assuming this," right? Or, like, I'm assuming that the stakeholder knows what they need [laughs]. And that's why we're going to do it this way, where we were kind of given the pieces of data that we should be persisting. And the more that we had that conversation, the more I realized, like, actually, like, I'm not convinced that they have that full picture of, like, what they need in the future. And because we're making this decision now, like, we are turning, you know, literally from, like, the abstract into, like, a concrete change [chuckles] in the database, now seems like...now that we're faced with that decision, it seems like a good time to revisit the assumption that I was making. And that has proved helpful in making ultimately, like, a more informed decision about, like, which way to go technically. But I personally have found a lot of value in verbally processing it with someone else. It's a lot harder for me to identify them, I think, when I'm in my own head. JOËL: That's really interesting that you keyed in on the idea of assumptions. I typically think of assumptions being, like, so important mostly in debugging rather than analysis. In fact, I wrote a whole blog post about why listing your assumptions is so important as part of your debugging process. Now, like, my mind is spinning a little bit. I'm like, oh, I wonder if I could use some of those, like, debugging techniques as part of more of my analysis step. And could that make me better? So, I think you've put me on a whole, like, thought track of, like, oh, how many of these debugging techniques can I use to make my analysis better? So, that's really cool. STEPHANIE: Yeah, and vice versa. So, a few minutes ago, I'd asked you how you make time for that analysis. Because I was thinking that, you know, in my day-to-day work, I'm juggling so many things. I often find myself running out of time and not able to do all of it. And that, I think, leads us really well into our topic for this episode, which is productivity tricks and ways that we make the most use out of our limited time. JOËL: I think I may have a maybe a bit of a controversial opinion on productivity tricks. I feel like a lot of productivity tricks don't actually make me that much faster. Like, maybe I save a couple of minutes a day, maybe 5 or 10 a day with productivity tricks. And, sure, that adds up over the course of a year. But there are other things I could do in terms of, like, maybe better habits, better managing of my schedule that probably have a much more significant impact. Where I think they are incredibly valuable, though, is not directly making me better with my time management but managing my focus, allowing me to kind of keep in the flow and get things done without getting sidetracked. Or just kind of giving me the things that I need in the moment that I need them so that I'm not getting on to a subtask that I don't really need to be doing. STEPHANIE: Yeah. I really like that reframing of what helps you focus because as I was brainstorming ways that I stay on track for my work, I think I ended up discovering a similar theme where it wasn't so much, like, little snippets and tools for me, as opposed to how I structure all of the noise, I guess, in my day-to-day work and being able to see what it is that I need to care about the most right now. JOËL: I think one of the things that I've tried to do for myself is to make it easy to have access to the information and the tools that I need. Probably one of the most useful bits of that is a combination of the documentation viewer Dash and the...I'm not sure what it would be called– launcher, productivity manager tool for Mac. Alfred, with a CMD + Space, it brings up this bar I can type into. And then you can trigger all sorts of things from there. And so I can type the name of a language or some kind of keyword that I have set up and the name of a method. And then, all of a sudden, it'll show me everything like, you know, top five results. And I can hit Enter, and it will bring up the documentation for that. So, if I want to say, oh yeah, what is the order of the arguments for Enumerable's inject method (which I constantly forget)? You know, it's a few keyboard shortcuts, you know, CMD + Space Ruby Enumerable inject. It's fuzzy finding, so I probably don't even need to type all of that. Hit Enter, and I have the documentation right in front of me. So, that makes it so that I can get access to that with very little amount of context shifting. STEPHANIE: Yeah. I like what you said about how the tools are really helping you, like, narrow down, like, the views of, like, what is most important for you in that moment, and it's doing a little bit of that work for you. I think the couple of tools and apps that I actually did want to share are kind of similar. One MacOS app I really like is called Rectangle for windows management, which is really crucial for me because I don't enjoy like, swiping and tabbing between applications. I would much prefer just seeing, usually, just two things. I try to keep my screen limited to two different windows at once because once it gets more than that, I'm already just, like, overwhelmed [laughs]. And as I'm trying to focus a little bit more on just having, like, one thing be the focus of my attention at a time, Rectangle has been really nice in just really quickly being able to do my windows resizing. So, I usually have, like, either things split between my screen half and half. Like, right now, I have your face on my screen as we record this podcast, and then my notes editing software for taking notes about what we talk about. During my development workflow, it's usually, you know, just my editor, my terminal, and then maybe my browser ends up being, like, the thing that I tab into. But I'm able to just, like, set that all up, and as I need those windows to change depending on what my focus has been shifted to, to kind of make more space for whatever I'm reading, or looking at, or processing visually. The keyboard shortcuts that Rectangle...that I have now, you know, ingrained into my fingers [laughs] has been really helpful. It's like, I'm not fussing with just, like, too many things open. JOËL: I have yet to, like, dive into a window manager. I'm still in the clunky world of CMD tabbing. But maybe I should give that a try. STEPHANIE: For me, it has helped even just, like, identify the things that I need to give more space to on my screen and aggressively, like, cut everything else [laughs]. So, that's a really great MacOS app. And then, the other one is actually kind of a similar vein. It's called Meeter, M-E-E-T-E-R. And it has been really helpful for managing my meetings, especially my video call meetings where the video call software that's being used for the meeting may be variable. And also, when I have multiple email addresses that meetings are being sent to, you're able to sign into all of your calendar accounts. And it provides a really nice view of all of your meetings. It has a really, like, minimal, I guess, design in your toolbar, where it shows you how many minutes until your next meeting. And from that toolbar button, you can click to go to the video conferencing software directly for whatever meeting is up next. And you don't have to, you know, scramble to open Google Meet, or Zoom, or Webex, or whatever it is. And that's [chuckles] been nice, again, just kind of, like, cutting down on the amount of stuff that I need to remember and shift through to get to my destination. JOËL: I think I'm hearing kind of two themes emerge out of some of the things that we've shared. And I'd like to maybe explore them a little bit; one is the power of keyboard shortcuts. And I think that's maybe what a lot of us think of when we think of productivity apps, at least developers, right? We love keyboard shortcuts. And then, secondly, I think I'm hearing automation, right? So, you don't have to go through and, like, find that email or calendar link to find the Zoom link or whatever. It shows up in your toolbar. So, maybe we can dig into a little bit of the idea of keyboard shortcuts. Are you a person who like customizes a lot of keyboard shortcuts? And is that a part of your kind of productivity setup? STEPHANIE: Well, a while ago, we had talked about not keyboard shortcuts in the context of productivity, but I think I had mentioned that I was trying to use my mouse less [chuckles] because I was getting a little bit of wrist pain. And I think that actually has rolled into a little bit of, you know, just, like, more efficient navigation on my computer. I think my keyboard shortcut usage is mostly around window management, like I mentioned. I do feel like I have, like, a medium amount of efficiency in my editor. Sometimes, when I'm pairing with other people who use Vim, I'm, like, shook by how fast they're moving. And I have figured out what works for me in VS Code, and I don't think I need to get any faster. You know, I've just accepted that [laughs]. In fact, it's almost, like, the amount of speed and friction that I have, in my experience, is actually a little more beneficial for the speed that my mind works [laughs]. It kind of helps me slow down when I need to think about what I'm doing as opposed to just, like, being able to, like, do anything at my fingertips, and kind of my brain is just not able to think that fast. And then navigating Slack, which is where I also spend a lot of my time on my computer. Now, using Slack with my keyboard shortcuts has been really helpful because, again, I'm not, like, mindlessly browsing or clicking around. I'm just looking at my unread messages. One non-keyboard shortcut I really like with Slack is Command + K, which is the jump-to feature. And so, I'm using that to go to a specific channel that I know I'm looking for or my own personal DMs, where I keep a lot of notes as well. And, honestly, I think that's, like, the extent of my keyboard shortcut usage. I'm curious what your setup is in regards to that, though. JOËL: I think I'm similar to you in that I have not kind of maxed out the productivity around keyboard shortcuts. You'd mentioned the jump to in Slack. Several pieces of software have something kind of like that. It might be some sort of omnibar, or a command palette, or something like that, where you really just need to know...CMD + K, or CMD + P, CTRL + P are common ones. Then you can sort of, like, type a few characters to just describe the thing you want to do, or a search you want to make, or something like that. Just knowing that one keyboard shortcut for your one piece of software gets you, I don't know, 80% of the productivity that you want. It's kind of amazing. I love the idea of an omnibar. STEPHANIE: Yeah, I hadn't heard of omnibar as a phrase before, but that feels very accurate. I like that a lot, too, where it's, like, oftentimes, I don't do whatever particular thing enough necessarily for it to justify a keyboard shortcut, for me at least. I'm still able to be fast enough to get to, like I said, that final destination or the action that I want to take with a more universal shortcut like that. JOËL: In my editor...so I use Vim, and I got used to Vim's keyboard-based navigation. And that is something that I deeply appreciate, maybe not so much for speed but being able to almost kind of feel one with the machine. And the cursor moves around, and I don't have to, like, think about moving it. It's really a magical sort of feeling. And it's become so much muscle memory now that I can just sort of...the cursor jumps around, things change out. And I'm not, like, constantly thinking about it to the point where now, if I'm in any other editor, I really want to get those shortcuts or, I guess, maybe not shortcuts but a Vim-style navigation, keyboard-based navigation. STEPHANIE: Yeah, it sounds like it's not so much the time savings but the power that you have or the control that you have over your tools. JOËL: Yes. And I think, again, the idea of focus. Navigation has stopped becoming a thing where I have to actively think about it. And I feel like I really do just sort of think my fingers are on the keyboard. I'm not having to, like, do a physical motion where I switch my hands. Like, I'm typing, and I'm writing code, then I have to switch my hand away to a mouse to shift around or, like, move my hand off the home row to, like, find the arrow keys and, like, move around. I just kind of think, and the cursor jumps up. It's great. Maybe I'd be the same if I'd put a lot of time into getting really good at, you know, maybe arrow-based navigation. I still think the mouse you have to move your hand off. It breaks just in the tiniest little way the flow. So, for me, I really appreciate being fully keyboard-based when I'm writing code. STEPHANIE: Right. Being one with the keyboard. As you were talking about that, I very viscerally felt, you know, when you encounter a new piece of technology, and you're trying to navigate it for the first time, and you're like, wow, like, that takes so much mental overhead that it's, you know, just completely disruptive to the goal that you're trying to achieve with the software itself. JOËL: Yeah, it is a steep learning curve. So, we've talked about custom keyboard shortcuts in the editor. But it's common for people to augment their editor with plugins, maybe even some kind of, like, snippet manager to maybe expand snippets or to paste common pieces in. Is that something that you've done in your editor setup? I think you said you use VS Code as your sort of daily editor. STEPHANIE: Yeah, that's right. I actually think I almost forgot about some of my little bits of automation because they are just so spelled for me [laughs] that I don't have to think about them. But you prompting me just now reminded me that there are a few that I'd like to shut out. Snippets-wise, I mostly use them for when I'm writing tests and just having the it blocks or the context blocks expand out for me so I don't have to do any of that typing of the setup there. And since I do use a terminal outside of my editor...I know that some people really like kind of having that integrated and being able to run tests even faster without having to switch to a different application, but I like having them separate. There is a really great plugin called Go to Spec where you can be in any, you know, application code file, and it will pull up the spec file for you. I've been really enjoying that, and that is what helps my test writing be a little more automated, even though I'm having it in separate applications. JOËL: That is really useful. So, as a Vim user, I also have a plugin that does something similar, where I can switch to what's considered the alternate for a particular file, which is typically the spec, or if I'm in the spec, it'll switch to the source file that the spec is testing. STEPHANIE: And then, I do have one really silly one, which is that I got so sick and tired of not remembering how to, you know, type the symbols for string interpolation in Ruby that has also become a snippet where the hash key and the [inaudible 28:48] brackets can [laughs] populate it for me. JOËL: I love it. So, Stephanie, I'd like to go back to something you were talking about earlier in the show. When you were sharing about what was new in your world and, you mentioned that you subscribe to the Substack and that you subscribe to, actually, a lot of newsletters, and you said something that really caught my attention. You were saying that you don't want these all cluttering up your email inbox. And instead, you send all of these to an RSS reader application. What kind of application do you like to use? STEPHANIE: I use Feedbin for this. And I actually think that this was recommended by Chris Toomey back in the day on a previous Bike Shed episode before you and I hosted the show. But that has been really awesome. It has a just, like, randomly generated email address you can use when you sign up for newsletters. You use that instead. And I really like having that distinction because I honestly treat my email inbox as a bit of a to-do list, where I am archiving or deleting a lot of stuff. And then the things that remain in my inbox are things that I need to either respond to, or do, or get back to in some way. And then yeah, when I've completed it, then that's when I archive or delete. But now that we do have all this great content back in email form, I needed a separate space for that, where I similarly kind of treat it as, like, a to-read list. And yeah, like, I look at my unreads in the newsletter RSS reader that I'm using and go through that when I'm in a blog-reading kind of mood. JOËL: I really like that separation because I'm kind of like you. I treat my inbox as a to-do list. And it's hard to have newsletters come in and, like, I'm not ready to read them. But I don't want them in my to-do, or, like, they'll just kind of sit there and get mixed in and maybe, like, filtered down to the bottom. So, having that explicit separation to say, hey, here's the place I go to when I am in a reading mood, then I can read things. I think there's also I've sort of trained myself to only check my email during certain times. So, for example, I will not check my work email outside of working hours. But if I'm on the subway going somewhere and I've got some time where I could do some reading, it would probably be a good thing to be going through some kind of newsletter or something like that. So, I either have to remember to go back to it, or what I tend to do is just scroll Twitter and hope that someone has shared that link, and then I read it there, which is not a particularly effective way of doing things. So, I might try the RSS feed reader tool. What was it called? STEPHANIE: Feedbin. JOËL: Feedbin. All right, I might try to get into that. STEPHANIE: Yeah, I look forward to hearing if that ends up working for you because I agree, having the two separate spaces has been really helpful because I don't want to get distracted by my email/to-do list inbox if I'm just wanting to do a bit of reading, enjoy some content. So, one more theme around productivity that I don't think we've quite mentioned yet, but maybe we've talked a little bit around, is the idea that it's, at least for me, it's a product of time and energy. So, even if you have all the time in the world, you know, you can just stare into space or, like, stare at a line of code and not get [laughs] anything done. JOËL: I know the feeling. STEPHANIE: Right? I am kind of curious how or if you have any techniques for managing that aspect. When your focus is low like, how can you kind of get that back so that you can get back to doing your tasks or getting what you need to do done? JOËL: If I have the time, taking a break is a really powerful thing, particularly taking a break and doing something physical. So, if I can go outside and take a walk around the block, that's really helpful. And if I need a shorter thing that can be done in, like, five minutes or something, I have a pull-up bar set up in my place. So, I'll just go up and do a few sets there and get a little bit of the heart rate slightly up, do a little bit of blood pumping. And that sometimes can help reset a little bit. STEPHANIE: Nice. Yes, I'm all for doing something else [chuckles]. Even when you know that this is a priority or is kind of urgent or whatever, but you just can't get yourself to do it, I've found that asking myself the question, "What would make this task easier for me right now?" has been helpful during those moments. And, for me, that might be grabbing a friend, like, maybe I'm blocked because I'm really just unmotivated. But having someone along can kind of inject some of that energy for me. And then, there's a really great blog post by a woman named Mandy Brown. It's called Energy Makes Time. And she talks about how doing the things that fill our cup, actually, you know, even though it seems like how could we possibly have time to be creative, or, like you said, maybe do something physical, those seem, like, lower on the priority list. But when you kind of get to the point where you just feel so overwhelmed and can't do anything else, and you just go do those things that you know feel good for you, you kind of come back with a renewed perspective on your to-do list. And you can see, like, what things actually aren't that critical and can be taken off. Or you just find that you have the capacity or the energy to get the things that you are really dreading out of the way. So, that has been really helpful when I just am feeling blocked. Instead of, like, feeling bad about how unproductive [chuckles] I'm being, I take that as a sign of an opportunity to do something else that might set me up for success later. JOËL: Yeah. I think oftentimes, it's easy to think of productivity in terms of, like, how can I maybe eliminate some tasks that are not high value through clever automation, or keyboard shortcuts, or things like that? But oftentimes, it can be more about just sort of managing your focus, managing your energy. And by doing that, you might have a much higher impact on both how productive you feel—because that's an important thing as well, in terms of motivation—and, you know, how productive you actually are at getting things done. STEPHANIE: Right. At least for me, like, not all TDM is bad and needs to be automated away, but, like, my ability to, like, handle it in the moment. Whereas yeah, sometimes maybe I've just run the same few lines that should be just a script [chuckles], that should just be, you know, one command, enough times that I'm like, oh, like, I can't even do this anymore because of just, like, other things going on. But other times, like, it's really not a big deal for me to just, you know, run a few extra commands. And, like, that is perfectly fine. JOËL: I love writing a good Vim macro. Yeah. So, it's important to think beyond just the fun tools and the code that we can write. Kind of think a little bit more at that energy and that mental level. That said, there are a ton of great tools out there. We've named-dropped a bunch of them in this episode. For our listeners who are wondering or who weren't, like, necessarily taking notes, we've linked all of them in the show notes: bikeshed.fm. You can find them there. STEPHANIE: On that note, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeee!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
Joël describes an old-school object orientation exercise that involves circling nouns in a business problem description. The purpose is determining which nouns could become entities or objects in a system. Stephanie shares she's working from the Hudson Valley in New York as a trial run for potentially relocating there. She enjoys the rail trails for biking and contrasts it with urban biking in Chicago. The conversation between Joël and Stephanie revolves around mentorship, both one-on-one and within a group setting. They introduce a new initiative at thoughbot where team members pair up with principal developers for weekly sessions, emphasizing sharing perspectives and experiences. Socratic method (https://tilt.colostate.edu/the-socratic-method/) Mentorship in 3 Acts by Adam Cuppy (https://www.youtube.com/watch?v=eDX5WH1uLz8) Exercism mentoring (https://exercism.org/mentoring) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: I was recently having a conversation with a colleague about some old-school object orientation exercises that people used to do when trying to do more of the analysis phase of software, ones that I haven't seen come up a lot in the past; you know, 5, 10 years. The particular one that I'm thinking about is an exercise where you write out the sort of business problem, and then you go through and you circle all of the nouns in that paragraph. And then, from there, you have a conversation around which one of these are kind of the same thing and are just synonyms? Which ones might be slight variations on an idea? And which ones should become entities in your system? Because, likely, these things are then going to be objects in the system that you're creating. STEPHANIE: Wow, that sounds really cool. I'm surprised that it's considered old school or, I guess, I haven't heard of it before. So, it's not something in my toolbox these days. But I really like that idea. I guess, you know if you're doing it on pen and paper, it's obviously kind of timeless to me. JOËL: And you could easily do it, you know, in a Google Doc and underline, or highlight, or whatever you want to do. But it's not an exercise that I see people really doing even at the larger scale but even at, the smaller scale, where you have maybe a ticket in your ticketing system, and it has a paragraph there kind of describing what needs to be done. We tend to just kind of jump into, oh, we're going to build a story and do the work and maybe not always think about what are the entities that need to happen out of that. STEPHANIE: I think the other thing that I really like about this idea is the aligning on shared vocabulary. So, if you find yourself using different words for the same idea, is that an opportunity to pick the vocabulary that best represents what this means? Rather than a situation that I often find myself in, where we're all talking about the same things but using different words and sometimes causing a little bit more confusion than I think is necessary. JOËL: Definitely. It can also be a good opportunity to connect with the product or businesspeople around; hey, here are two words that sound like they're probably meaning the same thing. Is there a distinction in your business? And then, you realize, wait a minute, a shopping cart and an order actually do have some slight differences. And now you can go into those. And that probably sparks some really valuable learning about the problem that you're trying to solve that might not come up otherwise, or maybe that only comes up at code review time, or maybe even during the QA phase rather than during the analysis phase. STEPHANIE: Yeah. I think that's really important for us as developers because, as we know, naming is often the hardest part of writing code, right? And, you know, at that point, you are making that decision or that distinction between maybe a couple of different terms that you're using to describe an idea and putting that down then will continue on to be read. And just propagating that down the line of, is this name actually what we mean? Or maybe we are using words that, at this lower level, make more sense, but when interacting or communicating with business stakeholders or product folks, they are using a different term. And I really like the idea of that activity being a cross-functional one where you can kind of agree on how to move forward there. Because lately, I've been finding myself oftentimes using both words where the product folks are describing it this way, and then we've, on the engineering side, have decided that, okay, we're actually going to call our database table this other thing, and now having to type out both [chuckles] meanings each time because I know that my audience is in both camps. JOËL: Yeah. There's, I think, a lot of value in using the business terms where possible. If you don't use them, there has to be a good reason. There's a slight distinction for the technical term. We're using it to say, hey, it's different from the business idea in interesting ways that only matter to the dev team. STEPHANIE: Is there a name for this activity? JOËL: I don't know, just circling nouns or underlining nouns. STEPHANIE: Cool. Maybe we can come up with something. [laughs] Or someone else can tell us if they know what this kind of exercise is called. JOËL: Gotta name the naming activity. So, how about you, Stephanie, what's new in your world? STEPHANIE: So, I have a pretty exciting life development to share. I am currently working from a different location than my home in Chicago. I'm in the Hudson Valley in New York for the next month because my partner and I are considering moving out here. And we are just kind of looking for a different pace of life a little bit. And we are taking this month as a trial run to see if we want to, you know, be out here permanently. And I've been having a great time so far. One thing that I've really enjoyed is all of the rail trails out here. So, a lot of old railroad tracks have been repurposed for outdoor recreation, and they are great for biking, or running, or even just walking. And I've been able to hop on my bike, you know, and bike a few minutes, and then I'm on the trail and just kind of surrounded by trees and forests. And that's been really nice because I missed having access to nature kind of, like, right outside my door. JOËL: So, you used to do quite a bit of urban biking in Chicago. But it sounds like now you're getting a chance to do more kind of nature biking. STEPHANIE: Yeah, it's a big difference for me because urban biking was always pretty rough or a little scary just, you know, having to bike with traffic. And I got a lot better at it. But now I'm, you know, biking completely off the roads. And I don't have to worry too much about cars. And I can, you know, just enjoy the fresh air around me and just be a lot more relaxed, I think, than I was able to when I was commuting in the city. JOËL: So, here's the real question. At this new location that you're staying at, do you have a bike shed? STEPHANIE: Not yet. But we now could have a bike shed because there's a lot more space out here, too. So, I could theoretically have my bike shed in my nice, big yard right next to my garden. And these are all [laughs] the hopes and dreams I have for my future life. JOËL: Before you build the bike shed, you can have six months of discussion about what color you want to paint it. STEPHANIE: Yeah, that's why I have this podcast, actually. [laughter] So, look out for that in what's new in my world is considering paint colors for a theoretical future bike shed in a place where I yet don't live. JOËL: You're going to become an expert in the Pantone color palettes. STEPHANIE: I hope so. That would be a great addition to my title. So, another thing that's new in both of our shared worlds is a new initiative on Boost, the team we're on, that you have been involved in. It's pairing sessions with the principal developer. JOËL: Yes. So myself and, another principal developer at thoughtbot have been doing weekly pairing sessions, where we take Tuesday afternoons and pair with one of the other members of the team on their client project doing whatever. So, it's not, a, like, pull someone in when you need help or anything that's more kind of targeted in that way. It's more of a you sign up for this ahead of time. And you just know that on this week, you get someone to pair with you who can hopefully bring in a different perspective a lot of experience, and pair with you on your particular project. STEPHANIE: Yeah. I'm so excited about this initiative because I've not been staffed on a project with you before or the other principal developer who's involved. And I have really wanted to work with you all and be able to learn from you. And I think this is a really cool way to make that expertise more accessible if you just don't happen to be working on a project together. JOËL: Yeah. One of the challenges I think of the principal role is that we want it to be a role that has a high impact on the team as a whole. But also, we are people who can be staffed on pretty much any client project that gets thrown at us and can easily be staffed on projects that require solo work. Whereas there are some teammates who I think it's the developer position that we guarantee they're never staffed solo. And so, that can often mean that our principals get staffed on to the really technically challenging problems or the solo problems, but then there's maybe not as much room to have interactions with the rest of the team on a day-to-day basis. STEPHANIE: Yeah. I think the key word you said that had me nodding my head was impact. And I'm curious what your hopes are for this effort and what kind of impact you want to be having for our team. JOËL: I think it's impact on a few different levels, definitely some form of knowledge sharing. Myself and the other principal developer have decade plus experience each in the field, have deep knowledge in a lot of different things like test-driven development, object modeling, security, things like that that build on top of kind of more basic developer skills that we all have. And those are all, I think, great ways that we can support our team if there's any interest in those particular skills or if they come up on a particular project. And knowledge sharing works both ways, right? I think anytime you're pairing with someone else, there's an opportunity to learn on both sides. And so, I think a really important thing when you're pairing with someone, even if you're kind of maybe more explicitly the mentor figure, is to kind of keep that open mind and look for not only what can I give, how can I teach, but what can I learn from this other person? STEPHANIE: Yeah, absolutely. I guess I'm wondering...and I know this is a pretty new programming so far, but is there anything you've learned or anything that surprised you that you weren't expecting when you, you know, first conceived of the idea based on how it's been going? JOËL: Something that really surprised me, there's some feedback I got after one of the pairing sessions, where this colleague who we'd paired together...and I felt like I hadn't contributed a ton, like, this colleague just really had it and was just kind of going through and doing things. So, I was kind of, like, leaving that pairing session being like, oh, I don't know if I added a ton of value here. And then, this colleague reached out to me and said, "Oh, you know, I felt, like, this huge boost of confidence because we were pairing together, and you were just kind of nodding along and basically saying yes to all of my choices." And I hadn't really considered that that can be a really valuable aspect of this sort of pairing. Sometimes you know the right thing to do, like, you've got it. But it's really easy to second-guess yourself. And just having someone along to, you know, give you that thumbs of like, yeah, this is the thing to do, can give you that confidence boost and kind of keep you moving in a way that feels really positive. STEPHANIE: Wow. I love that. That's really powerful, and I get that. Because, you know, obviously, it's very valuable to have your colleagues help generate different ideas that you might not have considered. But that validation can be really useful. And, you know, that's just not something you get when with a rubber duck. [laughs] The rubber duck can't respond, and [laughs] nod along. So, I think that's really cool that you were able to provide some of that confidence. And, in fact, I think that is contributing to their growth, right? In terms of helping identify, you know, those aspects that they're already really strong at, as well as developing that relationship so they know you're available to them next time if they do need someone to either do that invalidating or validating of an idea. JOËL: Yeah, there's a lot of power, I think, in kind of calling out people's strength and providing validation in a way that can really help someone get to the next level in their career. And it feels like such a simple thing. But yeah, sometimes you can have the biggest impact not by kind of going in and helping but just kind of maybe, like, standing back a little bit and giving someone a thumbs up. So, definitely one of the biggest surprises or, I think, one of the biggest lessons learned for me in the past few weeks of doing this. STEPHANIE: That's very cool. JOËL: So, Stephanie, you've also been doing some pairing or some mentoring from what I hear. STEPHANIE: Yeah. So, on my current client work, I have been pairing with a new hire on my client team who recently graduated from college. And this is his first job in software development. And I have been thinking and learning a lot through this experience because one of my goals was to get better at coaching, specifically the idea of asking guiding questions to help someone, you know, arrive at their own solution instead of, you know, making the suggestions myself or kind of dictating where to go. And this has kind of been a progression for me of kind of starting from, well, you know, I have the way that I want to do it. And the person I'm working with who maybe has less experience, like, they might not know where to go. So, we're just going to go along with my idea. And then the next step was offering a few different ideas, like a menu of options and kind of having that discussion about which way to go. And now, I really wanting to practice letting someone else lead entirely and helping them start thinking about the right things but ultimately not giving them the answer. But hopefully, like, the questions I've been asking means that they are able to get to a well-informed answer where they've thought through some of the things that I would think about if I were in the position of making the decision or figuring out how to implement. JOËL: Is this mostly asking questions to get them to think about edge cases, or is this, like, a Socratic approach to teaching? STEPHANIE: Could you describe Socratic approach for me? JOËL: So, the Socratic approach is a teaching approach that is question-based, where you kind of help the student come to the conclusions themselves by answering questions rather than by telling them the answer. STEPHANIE: Oh, interesting. I think a little bit of both. Where it's true, I am able to see some edge cases that folks with less experience might not consider because they just haven't had to run into them before or fight the fires when [laughs] their code in production ends up being a big issue or causes a bug. But I think that's just part of the work where there is kind of, like, a default dynamic that might be fallen into when two people are working together, and their experience levels differ, where the person who has less experience is wanting to lean on the more senior person to tell them where to go, or to expect to be in that position of just learning from them and not necessarily doing as much of the active thinking. But I was really interested in flipping that and doing a bit of a role reversal because I think it can be really impactful and, you know, help folks earlier in their career, like, really level up even more quickly than just watching, but actually doing. And so, the questions I've been asking have been a lot more open-ended in terms of, like, asking, "What do you think about this code that we're looking at?" Or, like, "Where do you want to go next?" And based on, you know, their answers, digging in a little more, and, at the end, maybe, like, giving that validation that we were talking about earlier. I was like, "Great. Like, I think that's a great path forward," or, "I think that's a good idea to spend our time on right now." But the open-ended questions, I think, are also ones that I also would have liked when I was in that position of learning, where having someone trust that I could draw on my past experience but, like, also knowing that they were there to support and maybe orient me if I ended up straying too far off the path. JOËL: How have you navigated situations where maybe you're asking a question about "What do you want to do next?" and they pick something that maybe would work but is not your sort of preferred approach, or maybe something that seems like it would work well enough but, you know, there's maybe a better approach? How do you navigate that? Do you let them take their approach and maybe kind of let them run into some of the edge cases and problems and then say, "Hey, let me show you something new"? Do you probe a little bit earlier? Or do you say, "Hey, that's good, but why don't we try my way"? How do you navigate that kind of situation? STEPHANIE: That is so hard. It's really challenging. Because if you kind of know that there's maybe a more effective way, or a cleaner way, or whatever, and you're seeing your pair or your mentee kind of go down a different path, you know, it's so easy to just kind of jump in and be like, "Oh, actually, like, let me save you some time, and effort, and pain and just kind of tell you that there's something else we could try." But I think I've been trying to sit on my hands a little bit and let them go down that path or at least let them finish explaining kind of what their thought process is and giving them the opportunity to do that act of thinking to see it through without interrupting them because I think it's really important to, you know, just honor the process that they're going through. I will say, though, that I also try to keep an eye on the time. And I am also, like, holding in my head a bit of a higher level, like, the project status, any deadlines, what's on our plate for the sprint. And so, if I'm seeing that maybe the path they want to go down might end up taking a while or we don't quite have enough time for that, to then come back and revisit and adjust and reiterate on, like, their first solution. Then that is usually an opportunity where I might offer them another way or say, like, "Hey, like, this is what I'm thinking," because of those things I mentioned before with deadlines or something I'm considering. But I generally try not to impose any of that as, like, this is what we will do so much as saying, "This is what I think we should do." Because I really want to hone in on the idea that, like, everyone just has opinions [laughs] about how they want to do things. And I'm not claiming mine is the perfect way or even the best way, but just what I'm thinking in this moment. JOËL: Yeah, time permitting, I've really appreciated scenarios where you give people a chance to do the non-optimal solution and run into edge cases that kind of show why that solution is not optimal and then backtrack out of it and then go to the optimal path. I think that's a lesson that really sticks much longer. So, I've even done that in scenarios where I'm building some training material. And I'll kind of purposely have the group go down the sort of obvious path, but that turns out to be non-optimal. And then, you hit a wall where things don't work, and then you have to backtrack. And it's like, okay, so that's why we don't do it that way that may have seemed obvious. Because then everybody remembers as opposed to...I mean, you could just go down this other path, and somebody asks you a question, "Why don't we go down this thing?" And then, they just...maybe they have to remember it, or it becomes a thing where it's like, oh, but, like, we were told that's a bad way to do it. And now you have this sort of, like, weird, like, absolutism about, like, oh, but, you know, Joël said that was bad. So, we just got to remember that's the bad thing. And it's not about the morality of that choice that I think can come through when you're kind of declaring a path good and a path bad, but instead, having experienced, hey, we went down this path. There were some drawbacks to it, which is why we prefer this other path. And I think that tends to stick a lot more with students. STEPHANIE: Yeah. I really like what you said about not wanting to inject that, like, morality argument or even kind of deny them the opportunity to decide for themselves how they thought that path went or, like, how they thought the solution was. If you just tell them like, "No, don't go there," you're kind of closing the door on it. And, yeah, they might spend a lot of time afterwards thinking that, like, that will always be a bad option without really forming an opinion for themselves, which I think is really important. Because, you know, once you do get more experience, that is pretty much, like, the work [laughs] that we're doing all of the time. But another thing that I think is also such a skill is assessing your own work, like, after you go down the path or, like, once you have something working, being able to come back to it and look at it and be like, oh, like, can this be better, right? And I think that can only happen once you have something to look at, once you have, like, a first draft, if you will, or do the less optimal implementation or naive implementation. JOËL: So, when you're trying to prompt someone to kind of build that skill of self-review or self-reflection on some of the work that they've done, how do you as a pair or a mentor help stimulate that? STEPHANIE: Yeah. I think with early career folks, one thing that is an easy way to start the conversation is asking, "Are there any places that could be more readable?" Because that's, I think, an aspect that often gets forgotten because they're trying to hold so much in their heads that they are really just getting the code to work. And I think readability is something that we all kind of understand. It doesn't include any jargon about design patterns that they might not have learned yet. You know, even asking about extracting or refactoring might be not where they are at yet. And so, starting with readability, for example, often gets you some of those techniques that we've learned that have, you know, specialized vocabulary. But I have found that it helps meet them where they're at. And then, in time, when they do learn about those things, they can kind of apply what they've already been doing when kind of prompted with that question as, like, oh, it turns out that I was already kind of considering this in just a different form. JOËL: And I think one thing that you gain with experience is that you have kind of a live compiler or interpreter of the language in your head. And so, sometimes for more complex code, I, as an experienced developer, can look at it and immediately be like, oh yeah, here's some edge cases where this code isn't going to work that someone newer to the language would not have thought of. And so, sometimes the way I like to approach that is either ask about, "Oh, what happens in this scenario?" Or sometimes it's something along the lines of, "Hey, now that we've kind of done the main workflow, there's a couple of edge cases that I want to make sure also work. Let's write out a couple of test cases." So, I'll write a couple of unit tests for edge cases that I know will break the code. But even when we write the unit tests, my pair might assume that these tests will pass. And so, we'll write them; we'll run them and be like, "Oh no, look at that. They're red. I wonder why." And, you know, you don't want to do it in a patronizing way. But there's a way to do that that is, I think, really helpful. And then you can talk about, okay, well, why are these things failing? And what do we need to change about the code to make sure that we correctly handle those edge cases? STEPHANIE: Yeah, that's really great. And now, they also have learned a technique for figuring out how to move forward when they think there might be some edge cases. They're like, oh, I could write a test, and they end up [laughs] maybe learning how to do TDD along the way. But yeah, offering that strategy, I think, as a supplement to having supported them in their workflow, I think, is a really cool way to both help them learn a different strategy or tactic while also not asking them to, like, completely change the way that they do their development. JOËL: So, we've talked about ways that we can coach and mentor in a more of a one-on-one setting. But it can also happen in more of a group setting. And an initiative that I've been involved in recently is, once a quarter, the principals on thoughtbot's Boost team are running a training session on a topic that we choose. And we chose this month to make it really interactive. We created an exercise. We talked a little bit about it, had people break out into breakout rooms for a pretty short time—it was like 20 minutes—and come up with a solution. And then brought it back to the big group to talk through some of the solutions. All of that within 45 minutes, so it's a very kind of dense-packed thing. And I think it went really well. STEPHANIE: Yeah. So, hearing that makes me think that the group wasn't actually going to get to a solution in necessarily that short amount of time. But I'm wondering if that was maybe intentional. Like it was never really about coming to the optimal solution but just the act of thinking about it or practicing how you would do that problem-solving without as much of a focus on the outcome. JOËL: So, yes and no. I think, as you said, the discussion, the journey is more important than the outcome. But also, because we wanted people to have a realistic chance at coming up with some kind of solution, we specifically said, "We don't want code. Don't write a code solution to this." Instead, we suggested people come up with some kind of diagram. So, the problem was, we have some sort of business process where you start by...you have an endpoint that needs to receive some kind of shopping cart JSON and then goes through a few different steps. You have to validate it. You have to attempt to charge their card, and then eventually, it has to be sent off to a warehouse to be fulfilled. And so, we're asking them to diagram this while thinking a little bit about data modeling and a little bit about potential edge cases and errors. People came up with some really interesting diagrams for this because there's multiple different lenses from which you could approach that problem. STEPHANIE: That's cool. I really like that you left it up to the groups to figure out, you know, what kind of tools they wanted to use and the how. You mentioned different lenses. So, I'm taking it that you didn't necessarily share what the steps of starting to consider the data modeling would be. Did you prompt the group in any way? How did you set them up before they broke out? JOËL: So, we had a document that had a problem definition; part of this involved talking to a few external services, so things like attempting to charge their card. I think there was a user service they needed to do to pull some user information. And then, there's that fulfillment center that we submit to the warehouse with your completed order. And so, we had sample JSONs for all of these. Again, the goal is not for them to write any code that deals with it but more to think about: okay, we need information from this payload to plug into this one. And then, if they want to add any sort of intermediate steps, they can do that. And I think sort of two common lenses that you could look at this is from more of an action standpoint, so to say, okay, well, first, we receive this payload, and then we make a call to this endpoint, and we try to do a thing and then success or failure, and then kind of go down this path and success or failure, and kind of keep going down that path until you finally reach that fulfillment endpoint. So, it's almost like a control flow diagram. But you could also take more of a data-centered approach and talk about how the data evolves as it goes through this process. And so, you start with, like, a raw JSON payload. And maybe that gets parsed into a shopping cart object, which then gets turned into a temporary order, which then gets turned into a validated order, which then is combined with a credit card charge to create a fulfillment order, which can then be sent off to the warehouse. And that perspective will completely change the way you think about what the code actually needs to be when you create it. STEPHANIE: Got it. That's cool. So, I'm curious, you know, what went into figuring out what the prompt would look like? I guess, like, where did you start? Did you already know that there would be these two different ways of thinking about or lenses to data modeling that you're, like, oh, like, maybe these groups will go down this route? Or was it, I guess, a bit of a surprise that when you came together, you found out kind of the different approaches? JOËL: We already knew that there would be multiple approaches, and we chose not to specify which one to take. I think now this is getting into almost like curriculum design and more kind of the pedagogy side of things, which I'm, you know, excited and passionate about. I don't know, is that something that you've done at all for some of your projects or areas where you've been coaching people? STEPHANIE: It's not been. But I actually do think it's a bit of a goal of mine to lead a workshop at some point at a conference because I really like the hands-on stuff that I get to do day-to-day, you know, working one-on-one with people. And, you know, I also am on the conference circuit. [laughs] And I was thinking that maybe workshops could be a really cool way to bring together those two things of like, well, I am enjoying that experience of working one-on-one, but it is, oftentimes, you know, just on our regular day-to-day work. And so, I would be really curious about how to develop that kind of curriculum for teaching purposes. Do you find yourself starting with problems you see on client work and kind of stripping that down into something maybe a little more general, or do these problems kind of just come up spontaneously? [chuckles] JOËL: So, workshop design is, I think, its own really fascinating topic, and honestly, we could probably do a whole episode on it. But the short of it is I typically work backwards from an end goal. So, just like when I'm writing a blog post, I have one big thing I want people to learn from a workshop, and then everything works backwards from there. Anything that is part of the workshop has to be building towards that big goal, that one thing I want people to learn. Otherwise, I strip it out. So, it's an exercise in ruthlessly cutting to make sure that I'm not overwhelming people and, you know, that we can fit in the time that we have because there's always not enough time in a workshop. And people can very easily get sidetracked or overwhelmed. So, as much as possible, have everything focusing in towards one goal. Circling back to the mentoring side of things, I'm curious what you see is maybe some of the biggest challenges as a mentor or a coach. STEPHANIE: Well, I think, for me, it was, in some ways, like, seeing myself in that role as mentor. Like, oftentimes, that was decided for me by someone else as, like, "Oh, hey. We have a new hire, and, like, would you be their onboarding buddy?" Or, you know, a manager kind of identifying, like, oh, like, Stephanie has been in this role for, you know, a few years now. She's surely ready to mentor [laughs] new folks or people joining the team. And that was really hard for me because I was like, well, I still have so much to learn [laughs], you know, like, how could I possibly be in that position now? You know, I am still learning from all these other people who are mentors to me. So, one thing that took me a long time was learning that I did have things that I knew that other people didn't. And I started to think of it more as this, like, ring of overlapping circles where, you know, we all probably do share some common knowledge. But we all are also experts in different things, and everyone always has something to teach. Even if you're just, like, a few months or, like, a year ahead of someone else, that is actually a really powerful spot to cultivate peer mentorship, and where I think learning can really thrive. There's a really great talk about this by Adam Cuppy called Mentorship in Three Acts, where he talks about that peer mentorship, where someone just knows, like, a little more than someone else. That can be really powerful and can be a good entry point for people who are interested in getting into mentorship but are kind of worried that, like, oh, they are, you know, not a senior yet. You know, when you're at a similar experience level as who you're working with, there is a little bit less of what we were describing earlier of, like, that dynamic of knowing what to do but kind of wanting to hold back and let them discover for themselves. In that peer mentorship dynamic, you know, both people are, like, really deep in it, kind of trying things out, experimenting, learning, and that ends up being really fruitful time for both of them. JOËL: Based on your experience, would you say that maybe that's the best place to start for someone who's looking to get into mentorship, so kind of pursue more of a peer mentorship scenario? STEPHANIE: Yeah. I would definitely say that it has helped me a lot. I've had a lot of peer mentorship relationships in the past, where maybe there just wasn't someone on the team who could mentor me at the time. Or maybe I was wanting to collaborate a little bit more and feeling like I did have some ideas and opinions that I wanted to talk about, or share, or get some feedback on. Reaching across my level was really helpful in starting to create that space. Yeah, I was really surprised by all the things that I was learning and all the things that the other person was learning from me that I think was a good wealth of experience for me to then bring to the next step when I found myself kind of in that position of supporting others who were more junior. JOËL: I'd like to also shout out Exercism.io as a great place to get started with mentoring. For those who are not aware, Exercism is a platform where they have a bunch of exercises that you can go through to learn a language. And you can go through them on your own, but you can also go through them with a mentor. Somebody will basically give you a little mini code review on your exercise or maybe help you out if you're stuck. And this all happens asynchronously. And it's volunteer-run. So, they just have people from the community who volunteer to be mentors on there to help coach people through the exercises. We'll put a link in the show notes to the page they have, kind of explaining how the mentorship works and how to sign up. But I did that for a while. And it was a really rewarding experience for me. I thought that I'd be mostly helping and teaching, but honestly, I learned so much as part of the process. So, I would strongly recommend that to anybody who wants to maybe dip their toe a little bit in the mentoring coaching world but maybe feels like they're not quite ready for it. I think it's a great way to start. STEPHANIE: Ooh, that sounds really cool. Yeah, I know that, especially for folks who maybe are working a little bit more independently, or are a bit isolated, or don't have a lot of people on a team that they're able to access; that sounds like a really great solution for folks who are looking for that kind of support outside of their immediate circle. On that note, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeee!!!!!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
Stephanie has another debugging mystery to share. Earlier this year, Joël mentioned that he was experimenting with a bookmark manager to keep track of helpful and interesting articles. He's happy to report that it's working very well for him! Together, they discuss tactics to ensure the easiest route also upholds app health and aids fellow developers. They explore streamlining test fixes over mere re-runs and how to motivate desired actions across teams and individuals. Raindrop.io (https://raindrop.io/) Railway Oriented Programming (https://fsharpforfunandprofit.com/rop/) Transcript: JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. STEPHANIE: And I'm Stephanie Minn. And together, we're here to share a bit of what we've learned along the way. JOËL: So, Stephanie, what's new in your world? STEPHANIE: So, I have another debugging mystery to share with the group. I was working on a bug fix and was trying to figure out what went wrong with some plain text that we're rendering from a controller with ERB. And I was looking at the ERB file, and I was like, great, like, I see the method in question that I need to go, you know, figure out why it's not returning what we think it's supposed to return. I went down to go check out that method. I read through it ran the tests. Things were looking all fine and dandy, but I did know that the bug was specific to a particular, I guess, type of the class that the method was being called on, where this type was configured via a column in the database. You know, if it was set to true or not, then that signaled that this was a special thing. You know, I made sure that the test case for that specific type of object was returning what we thought it was supposed to. But strangely, the output in the plain text was different from what our method was returning. And I was really confused for a while because I thought, surely, it must be the method that is the problem here [laughs]. But it turns out, in our controller, we were actually doing a side effect on that particular type of object if it were the case. So, after it was set to an instance variable, we called another method that essentially overwrote all of its associations and really changed the way that you would interact with that method, right? And that was the source of the bug is that we were expecting the associations to return what we, you know, thought it would, but this side effect was very subvertly changing that behavior. JOËL: Would it be fair to call this a classic mutation bug? STEPHANIE: Yeah. I didn't know there was a way to describe that, but that sounds exactly right. It was a classic mutation bug. And I think the assumption that I was making was that the controller code was, hopefully, just pretty straightforward, right? I was thinking, oh, it's just rendering plain text, so not [laughs] much stuff could really be happening in there, and that it must be the method in question that was causing the issues. But, you know, once I had to revisit that assumption and took a look at the controller code, I was like, oh, that is clearly incorrect. And from there, I was able to spot some, you know, suspicious-looking lines that led me to that line that did the mutation and, ultimately, the answer to our mystery. JOËL: Was the mutation happening directly in the controller? Or was this a situation where you're passing this object to a method somewhere, and that method, you know, in another object or some other file is doing the mutation on the record that you passed in? STEPHANIE: Yeah, that's a great question. I think that could have been a very likely situation. But, in this particular case, it was a little more obvious just in the controller code, which was nice, right? Because then I didn't have to go digging into all of these other functions that may or may not be the ones that is doing the mutation. But the thing that was really interesting is that it seems like that method that does this mutating is pretty key to the type of object that we're working with, as in most places it's used, that mutation happens. And yet, it's kind of separated from the construction of that object. And I was, I think, a little bit surprised that it wasn't super obvious that throughout the application, this is the way that we treat this special object. And I had wished that maybe that was a bit more cohesive or that it was kind of clear that this is how we use this in our domain. And it was, like, lacking that bit of clarity around how things are used in practice as opposed to trying to keep those in isolation. JOËL: Yeah. Because now you have sort of two different diverging use cases for using this object that are incompatible, one that's trying to use the object as is and the other that's depending on this mutation. Now you can't have both. STEPHANIE: Right. As far as I can tell, in most cases, you know, we're using it with a mutation, and maybe there is a good reason for those ideas to be separate. But it certainly did not make my life easier trying to solve this particular bug. JOËL: I'm hearing you mention the idea of ideas being separate; definitely kind of triggers some pathways in my modeling brain, where I'm already thinking, oh, maybe this should be a decorator, or maybe this is just a straight-up transformation. We just have a completely different kind of object rather than mutating the underlying record. STEPHANIE: Yeah, definitely. I think there could have been some alternative paths taken. At the time, that was kind of decided as the way forward for how to treat this particular domain object. So, that's my fun, little mystery where I got to, you know, play the detective role for a bit. Joël, what's new in your world? JOËL: So, earlier this year, on an episode of The Bike Shed, I mentioned that I was experimenting with a bookmark manager to kind of keep track of articles that I find are helpful that I might want to reference later on. I wasn't sure if it was going to be worthwhile and mentioned that I'd report back. I'm happy to report that it is working very well for me. So, the tool is Raindrop.io. They have an app. They have a website. And I have been sort of slowly filling it with some of my most commonly referenced articles. I had pulled some in initially, and then kind of over time, when I find myself referencing an article using my old-fashioned approach, which was just remember the keywords in the title and Google them, now I'll do that, link the article to someone else, and then add it to Raindrop so that the next time I'm starting to look for things, I have these resources available. And I try to curate a little bit by doing things like tagging them and categorizing them so that when I need references for something, I don't just have to go through my personal memory and be like, oh yeah, what articles do I have on data modeling that I think might be a good fit here? Instead, I can just go to the data modeling section of Raindrop and be like, oh yeah, these five are, like, my favorites that I link to all the time. STEPHANIE: Wow. We did a whole episode on how to search recently. And we totally forgot to mention things like bookmark managers or curating your own little catalog of go-to articles. In some ways, now you have to search within your bookmark manager [laughs]. JOËL: That's true. Sometimes, it's searching if I'm looking for a particular article, and sometimes, it's more browsing where I'm looking at a category, or a tag, or something like that, which maybe would have been another interesting distinction to explore on the How to Search episode. I do want to give a shout-out to the most recent article that I looked up in my bookmark manager here, Railway-Oriented Programming. It's an article on how to deal with pieces of code that can error and how to sort of compose those sorts of methods. So, you now have a whole sort of chain of different functions that can error or not in different sorts of ways. And it uses this really powerful metaphor of railway with different types of junctions and how you might try to, like, fit them all together so that everything connects nicely. And it's just a really beautiful metaphor. And I was doing some work on error handling, in particular, and I wanted to reference something and that was a great resource for that piece of work. STEPHANIE: Very cool. I'm really intrigued. I love a good metaphor. I am curious: is this programming language and framework agnostic and not about Rails? JOËL: Actually, so this is written on an F# blog. So, the code is all in F#. And it leans a little bit into some functional programming concepts, but the metaphor is more generic. So, it's a really fun way to think about when you're programming, and you're not just going through the happy path. But what are all the side branches that you might have to deal with, and how do those side branches come back into the flow of your program? STEPHANIE: Very cool. I can also see some really excellent visuals here if you were to use this metaphor as a way of understanding complexity. JOËL: Absolutely. In fact, this article has some pretty amazing visuals, so strong recommend. We'll link it in the show notes. STEPHANIE: So, a few episodes ago, we talked about code ownership at scale because my client project that I'm working on is for a company with hundreds of developers. So, it's quite a big codebase, quite a big team. One of the main issues that I, at least, struggle with on a day to day is flaky tests in CI. When I, you know, I'm wanting to merge a change, I often have to run the test suite a few times to get to green and be able to merge and deploy. And this is an interesting topic to me because when you're really trying to just get your changes through and mark that ticket as done, it's very tempting to just hit that, you know, retry button and let it sit and just hope for the best, as opposed to maybe investigate a little further about why that test was flaking and see if there's something that you could do about it. So, I wanted to talk to you about the idea of making the right thing easy or how, at both a team level and an individual level, we can set ourselves and our team up for success rather than shoulder this burden [laughs] and just assume that things are the way they are. JOËL: That's a really powerful question. Because I think by default, oftentimes, the less helpful thing is the path of least resistance, so, in this case, hitting that rerun button on a test suite, which I've absolutely done. But there's a lot of other situations in our work where, just sort of by default, the path of least resistance is the thing that's maybe less helpful for the team. STEPHANIE: Ooh, I noticed that you kind of reframed what I said. I was using the term, you know, the right thing, but you then reworded it into the helpful thing. And that actually gets me thinking about these words are kind of subjective, right? What is helpful to someone could be different to what's helpful to someone else. And I'm kind of curious about your definition of the helpful thing. JOËL: Yeah, I mean, sometimes it's very easy to sort of bring absolutes and [inaudible 11:26] judgments to code, you know, when we talk about writing good code, and being good programmers, being good at our jobs, not doing the bad things. And I think that sort of absolutism sometimes can, like, be very restrictive, and kind of takes us down paths that are not optimal for ourselves, for our teams, for our products. So, I'd like to think a little bit more relativistically have a little bit more of elasticity in the way that we formulate some of these ideas. STEPHANIE: Yeah. I really like that reframing, and I appreciate the nuance there. I think for me, when I think of doing the helpful thing, I'm hoping to ease the day-to-day workflow for other developers because that also includes myself, right? Like, I've certainly been there feeling frustrated or just kind of tired of retrying [laughs] the test suite over and over again. I'm also thinking about helpful, as in what will be helpful for future developers regarding the product? And can we make it robust now so that we're not dealing with bug reports later for things that we maybe we're trying to throw under the rug or just kind of glance over? Do you have any other guiding principles around what is helpful and what's not? JOËL: I think that the time horizon you mentioned is really interesting because you have to balance sometimes short-term value versus kind of long-term. And is it worth it to maybe not fix that flaky test today so that we can ship as soon as possible? Or is it worth investing a little bit of time today so that tomorrow or next week is better? If you're a solo developer on a tiny project, that might be of personal benefit only. But on a larger team, you know, that might benefit not just you but a larger amount of people. STEPHANIE: I just imagined the trolley problem [laughs] a little bit about, you know, the future developers and whose lives, not lives but whose happiness, the developer happiness you'll save [laughs] when you're on that track and making the decision about benefit now versus benefit later. JOËL: No connection to railway-oriented programming, by the way. STEPHANIE: I am really interested in also talking about barriers to doing the helpful thing or taking that extra step, right? Because I think identifying those barriers is really important to then, hopefully, break them down so that we are creating that path of least resistance. JOËL: That's interesting that you mentioned these as barriers because I think, in my mind, I was thinking about the same idea but from, like, a completely mirror perspective, the idea of incentives. Why do incentives push you in one way versus the other? STEPHANIE: I like that a lot. I think maybe there are, like, two different levers, right? Or maybe they are two sides of the same coin, where you do have incentive, and then you also have things that disincentivize you. JOËL: This reminds me a little bit of the idea of the tragedy of the commons. So, in the case of flaky tests, everybody as a whole on your project has a worse experience. And project velocity slows when there are flaky tests. But you, as an individual developer, are incentivized to ship features quickly and efficiently. And the fastest way you can get your individual feature to production is by hitting that rerun button. Even though, collectively as a whole, every time we do that, instead of fixing the flakiness, we're adding a tiny, little bit of extra slowness that will accrete over time. STEPHANIE: Yeah. It's kind of difficult to imagine really the negative impact that it's having collectively, right? You're kind of like, oh, I'm feeling this pain, but you're not always, like, really hearing about it from others, and we might just be silently suffering together [laughs]. I do think that once it's been identified as like, oh, like, we're all actually, like, really impacted by this, okay, great, let's make it a priority. And so, now, let's say I am slightly incentivized to go and investigate the flakiness of a test rather than hit the rerun button this time around. I am wanting to talk about those barriers I was referring to a little bit because I've been in this position where I'm like, okay, like, I have some extra time today. So, why don't I look into this? But then I go down that path, and now I'm looking at a test written by someone many years ago, you know, I don't know this person, and I don't know this domain. I don't know who to talk to to figure out even where to start. I may or may not feel equipped with the right tools to be able to address it. And then, I think the biggest challenge is not feeling like it matters, right? Once I'm hitting this barrier, I'm like, is it worth the effort? At that point, maybe a little bit demoralized because, well, this is just one, and we have so many other flaky tests, like, what's one more? JOËL: That's really interesting that you mentioned that sort of morale factor because it's absolutely the case on every flaky test suite I've seen. I think that kind of points to almost, like, an exponential cost to ignoring the problem. If someone fixed it early, yeah, it's slightly annoying, but you get it done. You fix it, and then you move on. When it feels like there's now this insurmountable pile of these and that any work you do here doesn't bring you any closer to the goal because it's effectively infinite, yeah, now, there is no incentive at all to do that work. STEPHANIE: So, to avoid that, we talked about incentives, right? And I'm kind of curious: what ways have you seen or experienced that did make you feel motivated to take that extra step or at least try to avoid that point of thinking that nothing matters? [laughs] JOËL: So, I'm going to start with, I think, what's maybe a classic developer answer, and I'm curious to get your thoughts on it because I think I have very mixed feelings about this. The idea of programmer discipline—we just need to kind of take more pride in our craft and pursue excellence, choose to do the right thing, even when it's hard every day. Because I hear a lot of that in our communities. How do you feel about that sort of maybe a bit of a mindset change? And how effective has that been? STEPHANIE: Whoa, yeah, that's a really great point because I think I also feel quite conflicted about it. Because sometimes I can find it in myself to be, like, you know, I have the energy today to want to uphold, like, a certain level of quality that would make me feel good about doing my best work. And then, there are other days where I am, you know, just tired, [laughs] or feeling a little bit lazy, feeling just not confident that it will be worth it. Because there's also, I think, some external forces, right? I've certainly been in the position where we were only rewarded or celebrated for shipping fast. That was the praise we were getting at retros. But then that actually really disincentivized me from wanting to do the helpful thing when the time came, right? When I'm in my development process, and I'm at, like, that crossroads. Because I'm like, well, I've been trying to do the right thing, but, like, no one is celebrating me for it. What if it takes away time from doing the thing that is considered successful? And, like, does it have an impact on me and my job? So, you can, you know, kind of go down that spiral pretty quickly. And, in that case, like, no amount of personal, like, individual [laughs] feelings of responsibility can really overcome those consequences if, like, you're working on a team where that is just simply not valued, and there are other people who have authority to impart consequences, I suppose. JOËL: Yeah. It's, you know, you have that maybe some amount of personal motivation. You feel like you're swimming upstream. And so, maybe the question then is, how do we reorient maybe some of the incentive structures in a team to try to make it so that if you are, let's just say, chasing some of those extrinsic rewards and you're trying to get praise from your teammates, or move forward in your career, whatever it is that is rewarded and valued on your team, how can that be harnessed to push people in a direction to get some of these extra tasks done? STEPHANIE: Yeah. I will say, though, it is a little bit of both. And I think that was maybe why we're both kind of conflicted about it. Because on the individual level and, in general, knowing what my values are and, like, wanting to do good work and uphold quality, there are times where I don't always behave according to those values. Like I said, I am feeling tired, or maybe it's, like, almost 5:00 o'clock, and I just want to, you know, push my thing [laughs] so I can go and go on with my day. What has helped me is having an accountability buddy. Maybe it's in code review, or maybe it's when I'm pairing, or maybe just talking about a problem that we're facing, right? And I might get into that sort of lizard-brain mentality of just wanting to do the easy thing. But as soon as someone else points it out or is, like, you know, like, "That's not quite aligning with what I know your, like, hopes and goals are for this project or how you want to do your work," usually, that's enough to be like, "Yeah, you're right." [laughs] And I'll take another pass at it. JOËL: And I think we've kind of come back full circle here in that you mentioned that sort of the lizard brain side of you wants to just do the easy thing with the implication that, in this case, the easy thing is the thing that's maybe not useful to the team long term. What if we could restructure things a little bit so that the easy thing was the most beneficial thing for the team? And now you're not having to use discipline to fight the lizard brain side of you, but you're actually working with it. One thing I've seen teams do with flaky tests is to not necessarily fix them immediately. Like, maybe you do rerun them, but when they happen, create a ticket for them and put them into the planning board. And so, now, these are things that get prioritized. They're things that might be fairly quick to do. So, it might be a fun, like, fast ticket for someone to pick up at the end of the week. It now counts towards velocity if tracked, so people, hopefully, get rewarded for doing that work. Is that something that you've seen? And how effective do you think that is in maybe making fixing flaky tests easier thing for a team? STEPHANIE: Yeah, that is actually something that we are doing on my team right now, and I think it's great. I like the idea of tracking it, right? Because then you could also see over time, like, whether we have been getting better at reducing flaky tests, you know, then it's also really clear when someone is preoccupied with that work, and they don't get assigned something else. One way that I've seen it not work as well as we hoped is when other work consistently gets prioritized over those flaky test tickets, and, you know, sometimes it happens. I think that's also information, though, about the team and how the team is spending its time compared to how the team thinks it should be ideally spending its time where, you know, we can say all we want, like, yes, like, we really want to make sure our test suite is robust. But when other things are consistently getting prioritized over it, then you can point to it and say, do we actually believe this if we're consistently not behaving according to that belief? I found that challenging to have that conversation. But I do think that the concreteness of adding it to our workload for a given period of time is at least providing information rather than it being things that, like, developers are doing one-off or kind of just on their own time. JOËL: Another solution that I've seen people do, and this is a classic developer solution, is tooling. If you have better tooling around a particular problem, sometimes you can shift that cost, that time of work it takes so that it's easier to do the best thing rather than to not...or at least make it easy enough that it's less of a big decision, like, oh, do I really want to invest that much work into something? And a classic example of this, I think, is when you're trying to get into more of a test-driven development workflow. Having a test suite that's fast and, really importantly, having a near-instant way to run a test from your code editor makes a big difference in terms of adopting that workflow. Because if the cost of running a test is too high, then yeah, the easy path is to just say, you know what? I'm not going to run a test. I'm going to just run it once at the end after I've written 100 lines of code or an entire feature. And now I am not getting the benefits of TDD. And that might kind of get into a negative cycle where because I'm not seeing the benefits, I do it even less. And then eventually, I'm just, like, you know what? Forget this whole thing. STEPHANIE: I think that also applies to testing in general, where if it, you know, is feeling really challenging. I have definitely seen people start to get into that mindset of, is this worth my time to do at all? And it's a very slippery slope, I think. That almost makes me think about, like, okay, like, what are some other ways to lift that task up and to elevate it into something that's worthy of saying, like, "Hey, like, that was really hard, and you did a great job. And that was really awesome that you persevered through that challenging thing." Sharing the pain points is really important, not only to, like I mentioned earlier, to, like, communicate that, oh, maybe, like, more people than you think are going through the same thing, but also to be able to identify when someone went out of their way to do the helpful thing and seeing that someone was willing to do it because, for them, being helpful is important. When I see someone on my team take on kind of a difficult task to make things easier for others and then share about it, I feel really inspired because I think, wow, like, that could be me as well. You know, there's that saying that many hands make light work. And I also think that's true of tackling these kinds of barriers, where if we all feel this collective responsibility or, like, wanting to help out the group, it ends up literally being easier. JOËL: I think something I'm hearing here as well is the value of giving praise. If somebody goes out of their way to make life easier for the rest of your team, give them a shout-out, whether that's in your team's Slack channel, maybe it's at an all-hands meeting, and you shout out some work that they've done or, you know, you put their name on a slide in your slide deck at some point, or whatever it is the mechanism within your team. Having a way to shout out people who've done some of this work that can be sometimes a little bit thankless is a great way to motivate seeing more of that. STEPHANIE: Yeah. I was just thinking that it can be really powerful because, like you said, a lot of it is thankless, but also, we may not even realize the impact it's having on others until you give that shout-out and express, like, "Wow, like, that change, you know, I've been bothered by this issue for so long and, you know, that really made an impact on me," just keeping that cycle of gratitude going. JOËL: So, I think we've kind of identified three maybe main areas of ways where you can help to incentivize these behaviors. You can do it through kind of process. We talked about the example of pulling the flaky tests as actual cards to be worked through on a board. It can be technical by introducing some tooling that makes it much easier to do the work that you're trying to do. And it can be personal by praising people, preferably in public, for taking that extra step. And I think all three of those can be part of a strategy to make it easier or more attractive for people to do work that benefits the team as a whole, even if they don't see an immediate return to that on a per-day level. STEPHANIE: Yeah. I like that we kind of talked about these three different categories. And people in all different types of roles can, hopefully, take something from what we've shared, right? If you are a manager or leader of a team, maybe you can investigate your processes. If you're an individual contributor and you notice your colleague doing something that you, you know, kept meaning to but just didn't have time for, recognize that work. It really does take a holistic approach, but I think an impact can be made at every level. JOËL: Agreed. I think for managers and more senior team members, that's really almost, like, part of their job description is to think about these kinds of things. How can we incentivize this work? How can we shift the team in a particular direction? There's a particular onus on them to do this right, to think about this, to model some of this behavior. STEPHANIE: Yeah, absolutely. JOËL: For someone who's really senior on a team also, they're often the ones who are tasked or who maybe take the initiative to build some of this more complex tooling so that these tasks are easier for more junior people. Maybe that's tinkering with some things and building an editor plugin that makes it easier to do some work. Maybe it's building a Rails generator so that the proper files get generated that maybe people wouldn't think to have when they're building certain work. Maybe it's building an RSpec matcher to make it easier for people to test some of the nuances of what we're hoping to do, catching some of these edge cases. Whatever it is, sometimes there are things that the more junior members of our teams aren't aware of, and having a senior person take time out of their day to build these things so that now the entire team can be more productive can be a really helpful thing to do. STEPHANIE: Yeah, that's a great point. And I think that also comes from having a pulse on what people are struggling with, right? So, you know, oh, it would be good to invest my energy into building a script to make this manual process easier because I keep hearing about people having issues with it or it being a challenge. So, I would even recommend posing the question of, like, how do people feel about being able to fix that flaky test, right? Like, is it intimidating? What are those barriers? Because your team knows best about what that experience is like. And if that is not something on your radar, maybe there are opportunities to incorporate it into where you're evaluating team morale and happiness. On that note, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
Joël shares he has been getting more into long-form reading. Stephanie talks about the challenges she faced in a new project that required integrating with another company's system. Together, they delve into the importance of search techniques for developers, covering various approaches to finding information online. Domain Modeling Made Functional (https://pragprog.com/titles/swdddf/domain-modeling-made-functional/) Episode on heuristics (https://www.bikeshed.fm/398) Episode on specialized vocabulary (https://www.bikeshed.fm/356) Episode on discrete math (https://www.bikeshed.fm/374) Joël's discrete math talk at RailsConf (https://www.youtube.com/watch?v=wzYYT40T8G8) Dash (https://kapeli.com/dash) Alfred (https://www.alfredapp.com/) Indiana Jones and the Crypt of Cryptic Error Messages (https://thoughtbot.com/blog/indiana-jones-and-the-crypt-of-cryptic-error-messages) Browser History confessional by Kevin Murphy (https://www.youtube.com/watch?v=R7LkHjJdH9o) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: Something I've been trying to do recently is get more into long-form reading. I read quite a bit of technical content, but most of it are short articles, blog posts, that kind of thing. And I've not read, like, an actual software-related book in a few years, or at least not completed a software-related book. I've started a few chapters in a few. So, something I've been trying to do recently is set aside some time. It's on my calendar. Every week, I've got an hour sit down, read a long-form book, and take notes. STEPHANIE: That's really cool. I actually really enjoy reading technical stuff in a long-form format. In fact, I was similarly kind of trying to do it, you know, once a week, spend a little bit of time in the mornings. And what was really nice about that is, especially if I had, like, a physical copy of the book, I could close my computer and just be completely focused on the content itself. I also love blog posts and articles. We are always talking on the show about, you know, stuff we've read on the internet. But I think there's something very comprehensive, and you can dig really deep and get a very deeper understanding of a topic through a book that kind of has that continuity. JOËL: Right. You can build up a larger idea have more depth. A larger idea can also cover more breadth. A good blog post, typically, is very focused on a single thing, the kind of thing that would really probably only be a single chapter in a book. STEPHANIE: Has your note-taking system differed when you're applying it to something longer than just an article? JOËL: So, what I try to do when I'm reading is I have just one giant note for the whole book. And I'm not trying to capture elements or, like, summarize a chapter necessarily. Instead, I'm trying to capture connections that I make. So, if there's a concept or an argument that reminds me of something perhaps similar in a different domain or a similar argument that I saw made by someone else in a different place, I'll capture notes on that. Or maybe it reminds me of a diagram that I drew the other day or of some work I did on a client six months ago. And so, it's capturing all those connections is what I'm trying to do in my notes. And then, later on, I can kind of go back and synthesize those and say, okay, is there anything interesting here that I might want to pull out as an actual kind of idea note in my larger note-taking system? STEPHANIE: Cool, yeah. I also do a similar thing where I have one big note for the whole book. And when I was doing this, I was even trying to summarize each chapter if I could or at least like jot down some takeaways or some insights or lines that I like felt were really compelling to me. And, like, something I would want to, in some ways, like, have created some, like, marker for me to remember, oh, I really liked something in this chapter. And then, from there, if I didn't capture the whole idea in my note, I knew where I could go to revisit the content. JOËL: And did you find that was helpful for you when you came back to the book? STEPHANIE: Yeah, it did. I usually can recall how, like, I felt reading something. You know, if something was really inspiring to me or really relatable, I can recall that, like, I had that experience or emotion. And it's just, like, trying to find where that was and that this is a system that has worked well for me. Though, I will say that summarizing each chapter did kind of remind me of, like, how we learned how to take notes in school. [laughs] And I think, you know, middle school, or whatever, I recall a particular note-taking format, where you, you know, split the page up into, like, an outline with all the chapters, and you tried to summarize it. And so, it did feel a little bit like homework [laughs]. But I can also see the value in why they taught me how to do that. JOËL: I was recently having a conversation with someone else about the idea of almost, like, assigning yourself the college-style essay question after finishing a book to try to synthesize what you learned. STEPHANIE: Whoa, that's really cool. I can see how that would really, like, push you to synthesize and process what you might have just consumed. And, also, I'm so glad I'm not in school anymore [laughs] so that I don't have to do that on a regular basis. [laughs] I'm curious, Joël, what book are you reading right now? JOËL: I've been reading Domain Modeling Made Functional, which is a really interesting intersection between functional programming, Domain-Driven Design (DDD), and a lot of interesting kind of type theory. And so, that sort of intersection of those three Venn diagrams leads to this really fascinating book that I've been going through. And I think it connects with a lot of other things that I've been thinking about. So, I'll be reading and be like, oh, this reminds me of this concept that we have in test-driven development. Or this reminds me of this idea that we do when we do a product design sprint. And this reminds me of this principle from object-oriented design. And now I'm starting to make all these really interesting connections. STEPHANIE: Awesome. Well, I hope to hear more about what you've learned or kind of what you're thinking about going through this book in future episodes. JOËL: This is not the last time we hear about this book, I'm pretty sure. So, Stephanie, what's new in your world? STEPHANIE: So, I have a little bit of a work update to share. So, lately, I've been brought in to work on a feature that is integrating with another company's system. And the way that I was brought into this work was honestly just being assigned a task. And I was picking up this work, and I was kind of going through the requirements that had been specked out for me, and I was trying to get started. And then, I realized that I actually had a lot of questions. It just wasn't quite fully fleshed out for the level of detail that I needed for implementing. And for the past couple of weeks, we've been chatting in Slack back and forth as I tried to get some of my questions answered. They are trying to help me, but also the things that I'm saying end up confusing them as well. And then, I end up having to try and figure out what they're looking for in order to properly respond to them. And I had not met these people before. These are folks from that other company. And, you know, I'd only just seen their little Slack profile pictures. So, I didn't know who they were. I didn't know what role they had and kind of, like, what perspective they were coming to these conversations from. And after a while, I was feeling a little stressed out because we just kept having this back and forth, and not a lot of answers were coming to fruition. And I really ended up needing the nudge of the manager on my client team to set up a meeting for us to all just talk synchronously. And I think I had...not that I had been avoiding it necessarily, but I guess I was under the impression that we were at the point where we could just, you know, shoot off a question in Slack and that there would be a clear path forward. But the more we kept pulling on that thread, the more I realized that, oh, like, we have a lot of ambiguity here. And it really helped to meet them finally, not in person but, like, over a video call. [laughs] So, this happened yesterday. And, you know, even just, like, going around doing introductions, like, sharing what their role was at the company helped me just understand, like, who I was talking to. You know, I realized, oh, like, the level of technical details that I had been providing was maybe too much for this group. And I was able to have a better understanding of what their needs were, like hearing kind of the problem that they had on their end. And I realized that, oh, like, they actually aren't going to provide me the details for implementation that I was looking for. That's up to me. But at least now I know what their higher-level needs are so that I can make the most informed decisions that I can. JOËL: Fascinating. So, you thought that this was going to be, like, the technical team you're going to work with. And it turns out that this was not who they were. STEPHANIE: In some ways. I think I thought by providing more technical details that would be helpful, but it ended up being more confusing for them. And I think I was similarly kind of frustrated because the ways that I was asking questions or communicating also wasn't getting me the answers that I needed as well. But I felt really great after the meeting because I'm like, wow, you know, it doesn't have to be as stressful. You know, when you start getting into that back and forth on Slack, at least I find it a bit stressful. And it turns out that the antidote to that was just getting together and getting to know each other and hashing out the ambiguity, which does seem to work better in a more synchronous format. JOËL: Do you have kind of a preference for synchronous versus asynchronous when it comes to communication? STEPHANIE: That's a good question. I think it's kind of a pendulum for me. I'm in my asynchronous communication is a bit better for me right now phase, but only because I am just so burnt out on meetings a lot of the time that I'm like, oh, like, I really don't want to add another meeting to my calendar, especially because...I amend my statement; I'm burned out of meetings that don't go well. [laughs] And this meeting, in particular, was different because, you know, I realized, like, oh, like, we are not on the same page, and so how can we get there? And kind of making sure that we were focused on that as an agenda. And I found that ultimately worked out better than the async situation that I was describing, which I'm thinking now, you know when things aren't clear, text-based communication certainly does not help with that. JOËL: So, meetings, sometimes they're actually good. STEPHANIE: Yeah, that's my enlightened discovery this week. JOËL: So, this episode is kind of a special one. We've just hit 400 episodes of The Bike Shed. So, this is episode number 400. It's also my 50th Episode as a co-host. STEPHANIE: Right. That's a huge deal. 400 is a really big number. I don't know if I've ever done 400 of anything before [laughs]. JOËL: The Bike Shed has been going on for almost ten years now. The first episode up on the website is from October 31st, 2014, so just about nine years from that first episode. STEPHANIE: Wow. And it's still going strong. That's really awesome. I think it's really special to be a part of something that has been going on for this long. And, I don't know, maybe there are still listeners today from back in 2014. I would be really excited to hear if anyone out there has been listening to The Bike Shed throughout its whole lifespan. That's really cool. JOËL: Looking back over the last 50-ish episodes you and I have done, do you have a favorite episode that we've recorded? STEPHANIE: This may be a bit of recency bias. But the episode that we did about Software Heuristics I really enjoyed. Because I think we got to bring to the table some of the things we believe and the way we like to do things and kind of compare and contrast that with each other. And I always find people's processes very fascinating. Like, I want to know how you think and where your brain is at when you approach a problem. So, I really enjoyed that topic. What about you? Do you have any highlight episodes? JOËL: I think there's probably two for me. One is the episode that you and I did on Specialized Vocabulary. I think this really touched on a lot of really interesting aspects of writing software that's going to scale, software that works for a team, and also kind of personal growth and exploration. The second one that I think was really fun was the episode I did with Sara Jackson as a guest talking about Discrete Math because that's an episode that I got really excited about the topic. And right after recording the episode, it was the last day of the call for proposals for RailsConf. And I just took that raw excitement, put together a proposal, hit submit before the deadline. And it got accepted and got turned into a talk that I got to give on stage. So, that was, like, just a really fun journey from exciting episode with Sara and then, like, randomly turned into a conference talk. STEPHANIE: That's awesome. That makes me feel so happy. Because it just reminds me about how the stuff we talk about on the show can really resonate with people, you know, enough to become a conference talk that people want to attend. And I also really like that a lot of the topics we've gotten into in the past 50 episodes when we've taken over the show have been a bit more evergreen and just about, you know, the software development experience and a little bit less tied to specific news within the community. Speaking of evergreen topics, today, I wanted to discuss with you an evergreen software skill, and that is searching or Search-Driven Development, even if you will. JOËL: Gotta always get that three-letter acronym, something DD. STEPHANIE: Yeah. I am really curious about how we're going to approach this topic because a lot of folks might joke that a big part of writing software is knowing what to Google. Do you agree with that statement or not? JOËL: Yes and no. There's definitely value in knowing what to Google. It really depends on the kind of work that you're doing. I find that I don't Google that much these days. There are other tools that I use when I'm particularly, like, searching through documentation, but they tend to be less sort of open-ended questions and more where it's like, oh, let's get the actual documentation for this particular class or this particular method from the standard library. STEPHANIE: Oh, interesting. I like that you pointed out that there are different scopes of things you might want to search for. So, am I hearing correctly that when you have something specific in mind that you are just trying to recall or wanting to look up, you know, you're still using search that way, but less so if you are trying to figure out how to approach solving a problem? JOËL: So, oftentimes, if I'm working with a language that I already have familiarity with or a framework that I have familiarity with, I'm going to lean on something more specific. So, I'm going to say, okay, well, I don't exactly remember, like, the argument order for Enumerable's inject method. Is it memo then item, or item then memo? So, I'll just look it up. But I know that the inject method exists. I know what it does. I just don't remember the exact specifics of how to do that. Or maybe I want to write a file to disk, and I don't remember the exact method or syntax to do that. There are some ways that you can do it using a bunch of instance methods. But I think there's also a class method that allows you to kind of do it all at once. So, maybe I just want to look up the documentation for the file class in Ruby and read through that a little bit. That's the kind of thing where I suppose I could also Google, you know, how to save file Ruby, something like that. But for those sorts of things where I already roughly know what I want to do, I find it's often easier just to go directly to the docs. STEPHANIE: Yeah, yeah, that's a great tip. And I actually have a little shortcut to share. I started using DuckDuckGo as my search engine in the past year or so. And there's this really cool feature called Bangs for directly searching on specific sites. From my search bar, I can do, let's say, bang Rails and then my query. And it will search directly the Rails Guides website for me instead of, you know, just showing the normal other results that might come up in my regular search engine. And the same goes for bang Ruby doc. That one shows ruby-doc.org, which is my preferred [laughs] Ruby documentation website. I've really been enjoying it because, you know, it just takes that extra step out of having to either navigate to the site itself first or starting more broadly with my search engine and then just scrolling to find the site that I'm looking for. JOËL: Yeah. I think having some kind of dedicated flow helps a lot. I have a system that I use on my machine. It is Mac-specific. But I use a combination of the application Dash and the application Alfred. It allows me, with just a few keyboard shortcuts, to type out language names. So, I might say, you know, Ruby inject, and then it'll show me all the classes that have that method defined on it, hit Enter, and it pops up the documentation. It's downloaded on my machine, so it works offline. And it's just, you know, a few key presses. And that works really nicely for me. STEPHANIE: Oh, offline search. That's really nice. Because then if you're coding on a plane or something, then [laughs] you don't have to be blocked because you can't look up that little, small piece of information you need to move forward. That's very cool. JOËL: That is really cool. I don't know how often I've really leaned into the offline part of it. I don't know about you; I feel like I don't code on airplanes as much as I thought I would. STEPHANIE: That's fair. I also don't code on airplanes, but the idea that I could is very compelling to me. [laughs] JOËL: Absolutely. So, that's the kind of searches that I tend to do when I'm working in a language that I already know, kind of a day-to-day language that I'm using, or a framework that I'm already pretty familiar with. And this is just looking at all the things I haven't gotten to the point where I've fully memorized, but I have a good understanding of. What about situations where maybe you're a little bit less familiar with? So maybe it's a new framework, or even, like, a situation where you're not really sure how to proceed. How do you search when there's more uncertainty? STEPHANIE: Yeah, that's a good question. I do think I start a bit naively. The reason that we're able to be more specific and know exactly where to go is because we've built up this experience over time of scrolling through search results and clicking, you know, maybe all of them on the first page, even, and looking at them and being like, oh, like, this is not what I want. And then, seeing something else, it's like, oh, this is more helpful and kind of arrived at sources that we trust. And so, if it's something new, I don't really mind just going for a basic search, right? And starting more broadly might even be helpful in that process of building up the experience to figure out which places are reputable for the thing that I'm trying to figure out. JOËL: Yeah, especially when there's a whole new landscape, right? You don't really know what are the places that have good information and the ones that don't. For some things, there might be, like, an obvious first place to start. So, recently, I was on a project where I was trying to do an integration between a Rails app and a Snowflake data warehouse. And so, the first thing I did—I'm not randomly Googling—I went to the Snowflake website, their developer portal, and started reading through documentation for things. Unfortunately, a lot of the documentation is a bit more corporatey and not really helpful for Ruby-specific implementation. So, there's a few pieces that were useful. There were some links that they had that sent me to some good places. But beyond that, I did have to drop to Google search and try to find out what kinds of other things the community had done that could be helpful. Now, that first pass, though, did teach me some interesting things. It gave me some good keywords to search for. So, more than just Ruby plus Snowflake or something like that like, I knew that I likely was going to want to do some kind of connection via ODBC. So, now I could say, okay, Ruby plus ODBC integration, or Ruby plus ODBC driver and see what's happening there. And it turns out that one of the really common use cases for ODBC and Ruby is specifically to talk to Snowflake. And one of the top results was an article saying, "Hey, here's how you can use ODBC to get your Rails app to talk to Rails." And then I knew I struck gold. STEPHANIE: That's really cool. The thing that I was picking up on in what you were saying is the idea of finding what is most relevant to you. And maybe that is something that the algorithm serves you because, like, it's, like, what a lot of people are searching for, you know, a lot of people are engaging with, or matching with all these keywords that you're using. My little hack that I've been [chuckles] using is to use Slack and lean on other people who have maybe a little more, even just, like, a little more experience than me on the subject, and seeing, like, what things they're linking to, and what resources they're sharing. And I've found that to be really helpful as a place to start. Because, at that point like, my co-workers are narrowing down the really broad landscape for me. JOËL: I really like how you're sort of you're redefining the question a little bit here. And that, I think, when we talk about search, there's almost this implicit assumption that search is going to be searching the public internet through Google or some other alternative search engine. But you're talking about actually searching from my private corpus of data, in this case, either thoughtbot or maybe the client's Slack conversations, and pulling up information there that might be much more relevant or much more specific to the work that you're trying to do. STEPHANIE: Yeah. In some ways, I like to think of it as crowd-sourced but, like, a crowd that I trust and, you know, know is relevant to me and what I'm working on. I actually have a fun fact for you. Did you know that Slack is actually an acronym? JOËL: No, I did not know that. What does it stand for? STEPHANIE: It stands for Searchable Log of All Communication and Knowledge. JOËL: That is incredibly clever. I wonder, is this the thing where they came up with that when they made the original name? Or did someone go back later on, you know, a few years into Slack's life and was like, you know what? Our name could be a cool acronym; here's an idea. STEPHANIE: I'm pretty sure it was created in Slack's early days. And I think it might have even helped decide that Slack was going to be called Slack as opposed to some of the other contenders for the name of the software. But I think it's very accurate. And that could just be how I use Slack. I'm a very heavy search power user in Slack. [laughs]. So, I find it very apt. You know, obviously, I use it a lot for finding conversations that happened. But I really do enjoy it as a source of discovery for a specific topic, or, you know, technical question or idea that I'm wanting to just, like, filter down a little bit beyond, like you said, the public internet. In fact, I have found it really useful for when you encounter errors that actually are specific to your domain or your app. Obviously like, you will probably be less successful searching in your search engine for that because it includes, you know, context from your app that other people in the world don't have. But once you are narrowing it down to people at your company, I've been able to get over a lot of troubleshooting humps that way by searching in Slack because likely someone within my team has encountered it before. JOËL: So, you mentioned searching for error messages in particular. And I feel like that is, like, its own, like, very specific searching skill separate from more general, like, how do I X-style questions. Does that distinction kind of line up with your mental map of the searching landscape? STEPHANIE: Yeah. I guess the way that I just talked about it now was potentially a bit confusing because I was saying instead of how you might search for errors normally, but I did not talk about how you might search for errors normally. [laughs] But specifically, you know, if I'm popping error messages into my search engine, I am removing the parts of the stack trace that are specific to my app, right? Because I know that that will only kind of, like, clutter up my query and not be getting me towards a more helpful answer as to the source of my issue, especially if the issue is not my application code. JOËL: Right. I want to give a shout-out to an article on the thoughtbot Blog with a wonderful name: Indiana Jones and the Crypt of Cryptic Error Messages by Louis Antonopoulos. All about how to take an error message that you get from some process in your console and how to make that give you results when you paste it into a search engine. STEPHANIE: I love that name. Very cool. JOËL: So, you've talked a little bit about the idea of searching some things that are not on the public internet. How do you feel about kind of internet knowledge bases, private wikis, that kind of thing? Have you had good success searching through those kinds of things? STEPHANIE: Hmm, I would say mixed success, to be honest. But that's because of maybe more so the way that a team or a company documents information. The reason I say mixed results is because, a lot of the time, the results are outdated, and they're no longer relevant to me. And it doesn't take that much time to pass for something to become outdated, right? Because, like, the code is always changing. And if, you know, someone didn't go and update the documentation about the way that a system has changed, then I usually have to take the stuff that I'm kind of seeing in private wikis with a bit more skepticism, I would say. JOËL: Yeah, I think my experience mirrors yours as well. Also, some private wikis have just become absolutely huge. And so, searches just return a lot of results that are not really relevant to what I'm searching for. The searching algorithms that these systems use are often much less powerful than something like Google. So, they often don't sort results in a way that are bringing relevant things up to the top. So, it's more work to kind of sift through all of the things I don't care about. STEPHANIE: Yeah, bringing up the size of a wiki and, like, all of the pages, that is a good point because I see a lot of duplicate stuff, but that's just, like, slightly different. So, I'm not sure which one I'm supposed to believe. One really funny encounter that I had with a private wiki, or actually it was, like, a knowledge base article that was for the internal team...it was documenting actually a code process. So, it was documenting in more human-readable terms, like the steps an algorithm took to determine some result. But the whole document was prefaced by, "This information came from an email that was sent way long ago." [laughs] JOËL: That's an epic start to a Wiki article. STEPHANIE: Yeah. And there was another really funny line that said, "The reason for this logic is because of a decision made by (This person's name.)," like a business decision that (some random person name). No last name either, so I have no idea [laughs] who they could be referring to and any of the, like, historical context of why that happened. But I thought it was really funny as just a piece of, like, an artifact, of, at the time, when this was written, that meant something to someone, and that knowledge kind of has been diluted [laughs] over the years. JOËL: Yeah, internal wikis, I feel like, are full of that, especially if they've had a few years to grow and the company has changed and evolved. So, now it's time for hot takes. STEPHANIE: Yeah, I'm ready for them. JOËL: We are now in the fancy, new age of AI. Is ChatGPT going to make all of this episode obsolete? STEPHANIE: I'm going to say no, but I'm also biased, and I'm not a ChatGPT enthusiast. I've said it on air. [laughs] I can't even say that I've used it. So, that's kind of where I'm coming from with all this. But I have heard from folks that, convenient as it may be, it is not always 100% accurate or successful. And I think that one of the things I really like about kind of having agency over my search is that I can verify, as a human, the information that I'm seeing. So, you know, when you're, like, browsing a bunch of Stack Overflow questions and you see, you know, all these answers, at least you can, like, do a little bit of, like, investigation using context clues about who is answering the question, you know, like, what experience might they have? If you encounter something on a blog post, for example, you can go to the about page on this person's blog and be like, who are you? [chuckles] And, like, what qualifies you to give this information? And I think that is really valuable for me in terms of evaluating whether I want to go down a path based on what I'm seeing. JOËL: So, I've played with it a tiny, little bit, so not enough to have a good sample size. And I think it can be interesting for some of those less constrained kind of how do I style questions. I'm not necessarily looking for, like, an exact code sample. But even if it just points me towards, oh, I need to be looking at this particular class in this standard library and read through that documentation to build the thing that I want. Or maybe it links me to kind of the classic blog posts that people refer to when talking about this thing. It's a good way sometimes to just narrow down when you're kind of faced with, you know, the infinity of the internet, and you're kind of like, oh, I don't even know where to start. It gives you some keywords or some threads to follow up on that I think can be really interesting. STEPHANIE: The infinity of the internet. I love that phrase. I don't think I've heard it before, but it's very evocative for me [laughs]. And I like what you said about it helping you give a direction and to kind of surface those keywords. In fact, it almost kind of sounds like what I was mentioning earlier about using Slack for, right? And, in that case, the hive mind that I'm pulling from is my co-workers. But also, I can see how powerful it would be to leverage a tool that is guiding you based on the software community at large. JOËL: Something I'd be curious to maybe lean into a little bit more are some of those slightly more specified questions where it does give you a code snippet, so something like writing a file to disk where, right now, it's, you know, five characters. I just pop up Alfred and type up Ruby F, and it gives you the file docs, and it's, you know, right there. There's usually an example at the top of the file. I copy-paste that and get working. But maybe this would be a situation where some AI-assisted tools would be better. It could be searching through something like ChatGPT. It could be maybe even something like Co-pilot, where, you know, you just start typing a little bit, and it just fills out that skeleton of, like, oh, you want to write a file to disk in Ruby. Here's how it's typically done. STEPHANIE: Yeah, you bring up a good point that, in some ways, even the approaches to searching we were talking about originally is still just building off of algorithms helping us to find what we're looking for, right? Though, I did really want to recommend an awesome talk from Kevin Murphy, from a RailsConf a couple of years ago, that's called Browser History Confessional: Searching My Recent Searches. The main message that I really enjoyed from this talk was the idea of thinking about what you're searching for and why because that will, I think, help add a bit of, like, intentionality into that process. You know, it can be very overwhelming, but let that guide you a little bit. One of the things that he mentions is the idea of revisiting your own assumptions with search. So, even if you think you know how to do something, or you might even know, like, how you might want to do it, just going to search to see if there's any other implementations that you haven't thought of that other people are doing that might inform how you approach a problem, or at least, like, make you feel even more confident about your original approach in the first place. I thought that was really cool. That's not something that I do now, but definitely, something that I want to try is to be, like, I think I know how to do this, but let me see what other people are doing because that might spark something new. JOËL: We'll put a link in the show notes to this talk. But I was lucky enough to see it in person. And also would like to second that recommendation. It is worth watching. From this conversation that you and I have had, I'm having, like, two main takeaways. One is kind of what you just said, the idea of being a little bit more cognizant of, what kind of search am I doing? Is this a sort of broad how do I X, where I don't even really know where to start? Is this, like, something really specific where you just don't know what kind of syntax you want to use? Is it an error message where you just want to see what other people have done when they've encountered this? Or any other, like, more specific subcategories. And how being aware of that can help you search more effectively. And secondly, don't limit yourself to the public internet. There's a lot of great information in your company's Slack or other instant messaging service, maybe some kind of documentation system internal, some kind of wiki. And those can be a great place to search as well. STEPHANIE: If we missed any other cool searching tips or tricks or ways that we might be able to improve our processes for searching as developers, I would really love to hear about them. So, if any listeners out there want to write in with their thoughts, that would be super awesome. On that note, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeee!!!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
Stephanie experienced bike camping. Joël describes his experience during a week when he's in between projects. Stephanie and Joël discuss the concept of code ownership, the mechanisms to enforce it, and the balance between bureaucracy and collaboration. They highlight the challenges and benefits of these systems in large codebases and emphasize that scaling a team is as much a social challenge as it is a technical one. Out Our Front Door (https://www.oofd.org/) Conway's Law (https://en.wikipedia.org/wiki/Conway%27s_law) Transcript: JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. STEPHANIE: And I'm Stephanie Minn. And together, we're here to share a bit of what we've learned along the way. JOËL: So, Stephanie, what's new in your world? STEPHANIE: This weekend, I went bike camping for the first time. So, it was my turn to try out the padded bike shorts and go out on a long ride, combining two things that I really enjoy: biking and camping. It was so awesome. We did about 30 miles outside of the city of Chicago to close to the Indiana border. And we were at a campground that's owned by the forest preserves where I'm at. It was so much fun. I packed all my stuff, including my tent and sleeping bags. And it was something that I never really imagined myself doing, but I'm really glad I did because I think it'll be something that I want to kind of do more of in the future, maybe even do multi-day bike camping trips. JOËL: So, what's your verdict on the bike shorts? STEPHANIE: Definitely a big help. Instead of feeling a little bit sore an hour or so along the bike ride, it kind of helped me stay comfortable quite a bit longer, which was really nice. JOËL: Would you do this kind of trip again? STEPHANIE: I think I would do it again. I think the next step for me is maybe to go even farther, maybe do multiple stops. Yeah, I was talking to my partner about it who came along with me, and he was saying, like, "Yeah, now that you've done that many miles in one day and, you know, camped overnight, you can really go anywhere. [laughs] You can go as far as you want." And I thought that was pretty cool because, yeah, he's kind of right, where I can just pack up and go and, you know, who knows where I'll end up? Not that I would actually do that because of my need to plan. [laughs] I'm not that go-with-the-flow. But there was definitely something really special about being able to get from A to B with just, like, my physical body and not relying on any other kind of transportation. JOËL: Yeah, there's a certain freedom to that spontaneity that's really nice. STEPHANIE: Yeah. And I actually went with a group called Out Our Front Door. And if anyone is in Chicago and is interested in doing this kind of thing, they do group bike camping adventures, and they make it really accessible. So, it's a very easy pace. You are with a group, so it's just really fun. They make it really safe. And I had a really great time. There was about 60 of us actually at camp, and they had rented out the entire campground, so it was just our group. And they even had a live reggae band come out and play music for us while we had dinner. And that was a really nice way for me to do it as a first-timer because there was stuff already planned for me, like meals. And I didn't have to worry about that because I was already, you know, just worrying about making sure I got there with all of my stuff. So, if that sounds interesting to you and you're in Chicagoland, definitely check them out. JOËL: That's a great way to bring in newer people to say, let's have a semi-organized thing, where all you have to focus on is the skill itself, you know, can I bike the 30 miles? Rather than planning all the logistics around it. STEPHANIE: Yeah, exactly. Joël, what's new in your world? JOËL: So, speaking of planning and logistics, this week, I'm in between projects at thoughtbot. And on the Boost team that I'm on, we've introduced a kind of special rotation for people who are in between projects where we have an internal project, where just internal strategic initiatives that we want to push forward. Whoever is unbooked gets to work on that. So, it's a small team with a very high churn. And one of the things that we do is every week; we have somebody act as the project manager for that team. And I was in between projects this week. I was assigned that project manager job. And so, I've been doing that in addition to some of the tickets myself, and that's been really interesting. STEPHANIE: Cool. I really like how that role is rotated among team members. JOËL: Yes. And the whole team itself is very high churn. So, somebody might be on that for just one week and then rotate off, and a new person comes in; maybe someone's on there a couple of weeks while we're waiting to find them a project. But we're always looking to prioritize booking people onto new client projects. And so, whoever is on that team, typically, is there for a short period of time. And so that means that the project manager role has to rotate a lot. But also, just in general, as you're managing tickets, you have to deal with the fact that people are not going to be on this project long-term. This is just, they're here for a few days, and they get some things done, and then they're moving off. And I think that presents some unique challenges in terms of the project management side of things. STEPHANIE: Yeah. What kind of challenges did you find interesting in this role for the week that you were on it? JOËL: So, in particular, I think making sure that outstanding work from the previous week gets done, especially when the people who were working on that ticket are no longer working on it. So, they may have done some partial work and then moved on to something else. And then, you have to ascertain the state of the ticket. Has it been completed? If it's only partial, what parts have and haven't? Can this be passed on to somebody else? Is there some unique knowledge that the previous person had? Has the code been pushed up? That kind of thing. STEPHANIE: So, that reminds me of something I heard about the idea of being expendable. You know, there are certain industries where anyone else with that skill set can kind of step in and take over for another worker without a lot of issues, and they can continue on doing that work. So, I'm thinking about, you know, maybe doctors or pharmacists where they have that, like, shared skill set, and everything is documented enough so that they can just take whatever their case is. And if someone is out, it's not a big deal because people can just step in. And I'm curious about if this is something that could work for software development. JOËL: I think it is important to have a team where nobody is irreplaceable. When it comes down to individual tickets, one of the things that I've been pushing for is that, at the end of the week, I would like to not see any tickets remain in the in-progress column. We're using a Kanban-style board. So, ideally, all work either moves to the done column or moves to the to-be-done column for next week. And it's no longer owned by anyone, so people have removed their faces from it. Ideally, though, if you pick up a ticket during the week, you get it to completion. So, one thing that I've been really pushing with our team this week is splitting tickets up. If this feels like it's bigger than a few days, then it needs to be split up, and part of it gets done moves to the done column. Part of it might be some work that somebody else is going to pick up next week; move that to the to-do column. And so, that way, at the end of the week, we have, ideally, a column full of things that were pushed over the finish line that are done. And then, we have a column of things to be done next week that nobody has kind of called dibs on yet. So that then next week, when we have a new group of people coming in, you don't just look at this column of to-do things. It's like, well, all of these have someone's face on them. I'm not able to pick up anything, so now what do I do? By having those all kind of fresh and available to be picked up, you make it easy for the next batch of people to hit the ground running on Monday morning. STEPHANIE: That's really interesting. You said you were doing this Kanban style, but it almost kind of sounds like one-week sprints in a way. JOËL: Kind of, because the way we book people onto clients is typically on a per-week basis. And so, if there's going to be a gap between clients, typically, it's in increments of a week. Because they're on the project for a week, it doesn't necessarily mean that we're tracking the tickets on a per-week thing. So, it's not like, oh, we're committing to doing all of these tickets by the end of a particular time or anything like that. We are working in a more Kanban style where there's a backlog, and you pull tickets, and whatever gets done gets done. What we do try to do, though, is not have individual tickets hang in the in-progress column over a week boundary. So, there's a nuance there. I guess there's some ways in which maybe it feels a little bit sprint-like. But I think we are running in much more of a Kanban-style workflow. STEPHANIE: Yeah, that makes sense. JOËL: It's really to deal with that churn and the idea that even though the ticket might stick around for a while or maybe it gets split up into multiple small tickets, the people are switching constantly. And so, making the workflow play nicely with the fact that the team is churning on a weekly basis kind of adds an extra, you know, a little bit of spice to the project management side of things. STEPHANIE: Did you find yourself being the one to break down tickets to make sure that they weren't larger than a week's worth of work? Or did you work with the developer themselves to find opportunities to break out what they were working on if we got to the mid-week and progress wasn't looking like it would be completed by the end? JOËL: I've left this up to individual developers. This is more of a broad conversation I had with our team, kind of saying, "Hey, here's our goal. We want to get some things done by the end of the week. If we don't think we can get them done, here are some strategies I recommend. I'm available to pair if people want it." But I didn't go through and estimate all the tickets and split them up. I did a little bit of, like, grooming ahead of time. So, I had a sense of when we started the week if tickets felt roughly sized correctly. But oftentimes, you know, that kind of thing, you start working on it, and then you realize, wait a minute, this is a bigger ticket than I thought. STEPHANIE: Yeah. I think even just having someone check in and be like, "Hey, how is progress? Can I support you in making sure that you're able to get to somewhere that feels completed by the end of the week so that the rest of the work is set up for someone new to take on?" That seems really valuable to me. Because as an individual, I'm like, yeah, I don't know, I'm maybe heads down just deep and trying to get my thing done, but maybe not so aware of progress and relative to how much time I've spent on it. And having just someone prompt me on that could help kind of pull myself out a little bit, you know, come out for some air and be like, oh, actually, you know, this is a good spot for me to break this down. Do you have any insights into this week that you might be bringing with you into client work or anything like that? JOËL: And I think this has just given me an even deeper appreciation for breaking tickets down. Because of that arbitrary end-of-the-week deadline, I think that forces more tickets to break down in a way that I might say, oh, well, I picked up a ticket on Thursday for a client. It can totally bleed into next week; that's fine. It's still a fairly short ticket, just, you know, I started the work later. And so, trying to make sure that tickets get scoped down really tightly, I think, is an area where I could probably benefit from that discipline on client projects as well. You know, even if I'm not doing it to the extreme, I'm doing it this week. STEPHANIE: Yeah. I would be really curious to find out if next week the folks who are on this project feel like they're in a good spot to, you know, keep on making forward momentum because they can just pull from the backlog and not have to go and do that knowledge transfer. JOËL: Right. I will see with all of this, right? Maybe even with all the conversations and things, maybe we'll end the week, and I'll have 10 cards in the in-progress column. And it'll be like, okay, we tried a thing this week, mixed success. How do we want to iterate on that idea next week? Potentially with a different team. STEPHANIE: Right, exactly. JOËL: I feel like one way to maybe summarize the type of work that I was doing this week is that it's a kind of a scaling challenge. But over time, the team itself is small, but it's constantly churning. And I think you've been working on a team where it's kind of had a similar problem but in a different dimension. You're scaling over team size, actually a massively large team, and seeing some of the challenges there. What are some of the things that you've been facing? STEPHANIE: Yeah. So, my current client project, I'm working on a codebase where there are hundreds of developers also working and committing to this codebase daily. And this codebase is really massive. There is so much stuff going on. And I've really only explored the world of the particular team that I'm on. But I recently had to do a little bit of work in some code that is owned by a different team. And I actually really appreciated the way that we were able to collaborate across, I guess, ownership boundaries. And I was really interested in talking about some of the different ways that we've seen the idea of, like, who is owning, and, like, who is accountable for areas of the codebase once you reach a certain size. So, what was really convenient about the way that I was working was that in my pull request, there was an automated step that told me I needed specific owner approval on the code that I was writing because I was touching some files that were owned by a different team. And it gave me all of the handles for the people on that team. So, I knew who to go talk to. And it ended up being that that team had a public Slack channel specifically for people outside to ask them questions about their domain. And they had a rotating ambassador system. And so, in the Slack channel, in the channel topic, it said who was the ambassador for that week. So, you know, I saw who it was. I got to @ them and say, like, "Hey, like, I'm working on some of these files for this feature for my team. And, like, here's my pull request. Could you give me a review?" JOËL: The more you're describing this, the more this is feeling very large team, almost bureaucratic systems. I'm hearing public Slack channels, which implies that teams have private Slack channels. I'm hearing, like, a rotating ambassador. One word that you mentioned that I'd like to dig into a little bit is the idea of ownership because I think that the concept of ownership is present on probably most teams, but it probably means wildly varying things. And it sounds like on your team, it's a very kind of codified thing. So, what does ownership look like on your project? STEPHANIE: Yeah, I love that you asked that question because you're right; it is codified, literally, in the codebase. There are ownership files that are in the repo itself where they've specified, like, all of the models that a team owns, you know, down to the names of the files themselves, or maybe a namespace. It has the team name and all of the team members' handles. So, that's how it was able to tell me in an automated way, like, hey, reach out to these people. It was really interesting because it was pretty frictionless on my end, where all I had to do was see that, you know, I couldn't submit my pull request until I got that approval. But it was enough friction to be, like, well, you can't just, you know, change files in this domain without someone with extra context taking a look. JOËL: This reminds me a little bit of a system that GitHub has where you have this CODEOWNERS file that you can add to a repo. Have you messed around with that at all, or kind of seen how that looks? STEPHANIE: I have a little bit. I think I've only seen it in the context of being notified that someone is wanting to submit a pull request, but I'm not sure if it does gate merging based on ownership. Do you know if that's the case? JOËL: I don't. I think you can set it up to automatically request reviews from owners. And on a large repo, the owner could be...I assume this is based maybe on directories, or it might be a regex pattern. I forget the exact details. But you can have owners for partial parts of the code instead of owners of the entire repository. So, then, if you make a change to a particular part of the code, it would ping the correct person automatically to review your code, which sounds like a really nice feature. STEPHANIE: Yeah, absolutely. I think for the project that I'm working on, this definitely seemed like a custom process that they, at one point, decided to enforce. I'm not really sure about the history of how this came to be. But I found it actually quite a good way to meet people who are working in other parts of the codebase. The person who happened to be ambassador that I pinged was so helpful in just, you know, making sure that I kind of understood the parts of the code that they owned that were honestly, like, quite complex. Like, I would not have felt confident just going ahead and making those changes necessarily myself because this is a pretty legacy codebase. There are quite a few gotchas, and they were able to point some [laughs] of them out to me. Yeah, having that extra confidence was helpful for the particular feature I was working on. But it did also kind of give me a little pause because I've not worked at such a scale where there was so much uncertainty about the domain and that being so diffused across like I mentioned, hundreds of people. JOËL: Do you think that this ownership system that's in place helps manage the complexity of scaling up to a team of hundreds of developers? Or does it feel like it kind of just adds a lot of process that gets in your way? STEPHANIE: Ooh, that's a good question. It seems like kind of a chicken-and-the-egg situation because I felt better with someone else's input, right? Like, with someone else with more domain knowledge than me about what I was touching to be, like, "Yeah, like, this looks good to me," giving the plus one. Whereas if that didn't exist, maybe I would have tried to seek it out on my own. But I would not have known where to start, right? I would have to ask around and be like, "Hey, like, who has worked in this directory before?" or whatever. Or I could have just went ahead and merged my code and hope my lack of context didn't really cause any huge problems, like outside of what was covered by the tests. But this is helpful for, like, where the codebase is at, you know, and the size it has grown. JOËL: Do you think requiring an owner to review the code puts maybe an undue burden on the person who's the owner and that they might end up spending a lot of time reviewing code because they now kind of manage that part of the app? STEPHANIE: Yeah, that's a really good question. I think it can. But I also feel a little better that that role is rotated, that everyone on the team gets the opportunity to really, like, focus on that. And I'm pretty sure the way it works is that that is their main focus for the sprint, or the week, or whatever, and that they're not assigned any other feature work but to prioritize being that ambassador. So, in some ways, that is a lot of process, right? And there is that trade-off of having to allocate someone specific to answer people's questions. But at least from what I've seen, it does seem like a necessity because people do have questions, right? And I think they have figured out a system where it's very clear who you're supposed to talk to, and that accountability aspect of it has been met. Because I've also, like, worked on teams where that role is not well defined. People don't want to do it. And it's almost kind of a bystander effect where someone asks a question, but no one is specifically responsible for answering it, and so no one answers it. JOËL: Oh yeah. Yes. And then you get kind of the cost of the bureaucracy without the benefits of kind of diffusing that knowledge. So, we've been talking a lot about how this kind of ownership system can be really beneficial despite the overhead for a team that's 200 or 300 developers and where nobody knows all of the code or all of the nuances. And kind of at the other extreme, it's absolutely not worth it for a team of two or three developers where everybody knows the code, and there's kind of shared ownership of the project. Somewhere in between, there is where you start having maybe some of those conversations about scaling the team, and do we need to introduce more process? In your experience, where do you think introducing some sort of ownership system like this starts becoming valuable? Or maybe what are some of the questions that a team should ask themselves to gauge, like, at the size we're at right now, would we get value from an ownership system? STEPHANIE: Yeah, that's a really good point because as you were saying that, I was just starting to think of, yeah, I've certainly worked on projects where I have reviewed every piece of code that is to be merged, right? And then, at some point, that starts to change where, like, I can't do that anymore. And that transition has always been really interesting to me. And then, I think there is, like you mentioned, another one where it's like, okay, now we aren't able to review everything, but, like, how do we trust that the code that is being merged, even if we don't all share that same context, is up to the quality we want it or is bug-free? Because without that context, there's always the opportunity that something might be missed. I think I've seen that on teams, you know, really look like more bugs than usual, right? And maybe there is, like, actually, like, a big problem, and the site is down. And maybe there is, like, a post-mortem or something to discuss, like, why this happened. And, you know, it turns out that the siloing or, like, the lack of context sharing was partly involved. And so, I do think there are definitely symptoms when we're starting to firefight a little more [chuckles] that might be kind of an indicator that the app has grown to a point where some context is being lost, and there are not guardrails in place to do our best to, like, share it, like, when we can and not when it's too late. JOËL: Would it be fair to say that your recommendation is the team should not have an ownership system and kind of stick to everybody reviews all the code as they grow until they start hitting actual pain points, such as real bugs caused and, at that point, let that pain or maybe even the post-mortem be the thing that triggers the introduction of an ownership system? STEPHANIE: I think so. I have not seen something like that proactively introduced. I would be curious if anyone has experienced something like that. But, you know, I think it's okay for change to be a little painful, right? And that's part of the growing pains of becoming a larger team, or organization, or codebase and continuing to reevaluate. Though, I guess I would be a little cautious about, you know, jumping straight to introducing processes or policies, right? Because those can be really hard to undo if they end up not being actually helpful for the root cause of the problem. But, like, how you experimented with making sure that, you know, we didn't have any in-progress tickets for that project. The idea of just trying something and seeing how it works and kind of getting the team's feedback that is really valuable to me, at least as an IC. And, yeah, just making sure, like, you know, hearing from all of your team members on how those processes are changing the way they work and if it's feeling good or not. Like I said, I enjoyed the process on my client project because it helped me feel more confident that the code that I was changing...because I can't possibly gain all of the knowledge that the owners of that area of the code have. It's just not going to happen. But also, I can imagine it being maybe not so good for someone else, right? It kind of being a barrier or being frustrating because, oh no, they really need to merge the code. And maybe they made the smallest change in a file owned by another team, right? And having to jump through that hoop. JOËL: Yeah, that has absolutely never happened to me. STEPHANIE: Really? Because it sounds like it has. [laughter] JOËL: Yes, it absolutely has. We've been kind of throwing around the idea of ownership the idea of team almost interchangeably as if they're one-to-one. And I want to lean a little bit into this idea of the team. Because I think there's an implicit assumption here that, within a team, there's enough knowledge sharing that happens, enough shared context, that everybody can kind of understand all of the code for their team, and that knowledge is just shared around, so you don't need these extra processes within teams. But maybe once you start having multiple teams as part of your engineering department, then there starts to be some friction or some lost context that needs some mechanism to get around. Does that sound about right to you? STEPHANIE: Ooh, I think that depends because even within my team, we are working on different projects, and I am definitely not on top of, you know, what some other folks are working on. And even within our team, there are silos. The difference there, though, is that I know who they are. Like I still am in contact with them in our daily syncs, that the barrier to finding someone who has the right information is much lower. So, yeah, I think that is definitely a part of it, too, if, like...I think just the social barrier, even of, like, reaching out to someone you don't know and being like, "Hey, like, can you review my code?" that is [laughs] kind of...can be a little scary. And the dynamics definitely feel different within a team and between teams. JOËL: Yeah, and definitely just the idea of, like, someone you see every day for your daily sync, you're going to feel much more comfortable reaching out to them for help or for a quick review than to a total stranger. So, it's interesting that you mentioned the social aspects of things. I don't know if you're familiar with Conway's Law, the idea that the technical structures of our code, over time, end up reflecting the social structures of our teams. STEPHANIE: Yeah, that is something that makes a lot of sense on the project that I'm working on now, where the boundaries, like I mentioned, between teams and between different namespaces are semi-rigid, I suppose, right? Rigid enough that, you know, there is a process but not so high that it becomes a burden, at least in my opinion. But for another feature that I worked on, I actually had to interact with an external system that's owned more by the parent company of my current client. And that process was definitely more rigid. And I had to figure out who to email and had to, you know, look up this person's profile in the company directory to make sure that, you know, I was talking to the right person who had information that was relevant to me. And then, you know, even, like, the technical aspect of talking to this external service had a lot of various barriers and, you know, special authorization and configuration that I needed to set up. So, definitely felt that in terms of the different levels of ease and talking to systems owned by different parties. JOËL: So, the fact that there's, like, an actual, like, departmental or even, like, corporate boundary, definitely showed up in, like, a very hard boundary in the code as well. STEPHANIE: Yeah, absolutely. JOËL: And I think taking this to an extreme, I've seen this happen when teams want to introduce microservices. And oftentimes, the boundaries of those microservices are not necessarily driven entirely by technical reasons, but they're often by social reasons. So, we can say, hey, this team is going to own this service, and everybody else only needs to interact with a public API. And we can make all sorts of changes internally, and you never need to know that. They will never break your code. And also, we don't need to bother each other or feel the need to fully deeply understand the internals of each system. STEPHANIE: Yeah. Once you're introducing APIs that are accessible to a certain group of people and having to navigate, you know, making changes to the API or aligning in the expected structure of the, you know, communication that you're sending between them, that is definitely a pretty rigid boundary [laughs] and ends up being a lot of overhead to talk to those systems. And I certainly have been in the position of trying to communicate with the people who built and designed those systems and figuring out how to get on the same page. And even just recently, I was accidentally sending something as an array, and they were expecting it as a string. And that caused all these problems of making the request happen, you know, successfully. And we didn't even realize it until someone pulled out the doc that had the API schema and pointed out that there was some miscommunication along the way. JOËL: And that can be such a hard boundary around even, like, the idea of ownership. So, you were talking about how, earlier, when you were working in code that's maybe owned by another team, they might want to review it before it gets merged. So, there's a bit of a gatekeeping there. When a team transitions fully to microservices, I've seen it go almost, like, more extreme where it's even, like, you don't even change the code. You submit a ticket into our system. We will prioritize it, and then eventually, we will build your feature. But you don't even get to make a change to the code and have us approve it. We're going to make all that because we own it. So, it kind of feels like taking that ownership idea and then just really running to a full extreme. STEPHANIE: Yeah, right. That makes a lot of sense in the lens of Conway's Law if those are the processes they have in place for navigating cross-team collaboration or communication. Because, at some point, maybe they just reached a level where it had to be enforced that way because maybe things were getting dropped, or more casual lower barrier connection was too overwhelming or just not working for the organization. JOËL: I think what I've been hearing just now and then just more broadly throughout the episode is that while there's a lot of interesting technical solutions that can make things better, at its root, scaling a team is a social problem. And it's all about how your teams communicate with each other so that you can scale smoothly and that the system doesn't suffer from adding more people. STEPHANIE: Yeah. I think this is an area where I would love to hear any thoughts from our listeners about how their organizations handle something similar because I find all of this really interesting. And, you know, it ends up impacting my day-to-day work in a very real way. And so, if other places have figured out how that scaling and, you know, social and technical boundaries work in a way that feels good, I would love to know. JOËL: On that note, shall we wrap up? STEPHANIE: Let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
Want a cool cucumber salad? Joël's got you covered. Stephanie has evolved and found some pickles she enjoys. Experienced programmers use a lot of heuristics or "rules of thumb" about what makes their code better. These aren't always true, but they work in most situations. Stephanie and Joël discuss a range of heuristics, how to use them, how to come up with them, how to know when to break them, and how to teach them to more junior devs. Pickled mustard seeds (https://www.youtube.com/watch?v=aLMFGk7Ylw0) The purpose of a system is what it does (https://en.wikipedia.org/wiki/The_purpose_of_a_system_is_what_it_does) Intro to empirical software engineering by Hillel Wayne (https://www.youtube.com/watch?v=WELBnE33dpY) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: So, as of the recording of this, summer is in full swing, and it's the time of year where we have all these, you know, fresh vegetables out, so I've been really enjoying a lot of those. I think this week; in particular, I've been going into, like, all the variations on cucumber salads. STEPHANIE: Ooh. JOËL: Yeah. So, that's been kind of fun for me. A fun thing I've been doing to spice this up is pickling mustard seeds to add as a topping. That's actually really amazing. It adds just a little bit of acidity, a little bit of crunch, a little bit of texture. And it's pretty. STEPHANIE: That sounds so delicious. And also, I was going to share something about pickles about what's new in my world. [laughs] But first, I am curious, what has been your go-to cucumber salad that you put this pickled mustard seed situation on top? JOËL: So, cucumbers and tomatoes is just the base of everything. And then, it kind of goes with random things I have in my fridge. A little bit of goat cheese on top can be a great topping, big fan of balsamic glaze. You can just get, like, a bottle of that at the grocery store, the pickled mustard seeds. I've recently been trying topping with a fried egg. STEPHANIE: Ooh, that sounds really fun. It kind of, like, adds a bit of savoriness and creaminess and maybe even, like, the crunchy fried edges. That sounds really yummy. JOËL: Particularly if you do it over easy where the center is not fully cooked. When the egg breaks, you effectively get salad dressing for free. STEPHANIE: That sounds so delicious. JOËL: Summer vegetables, they're great. STEPHANIE: They are great. Last year, I did have a cucumber garden, as in a garden, and a few cucumber plants that were too prolific for me, to be honest. I found myself overrun with cucumbers and having to give them away because we just didn't eat them enough. And this year, we scaled back a little bit [laughs] on the cucs. But I am so excited to bring up what's new in my world now because it's, like, so related, and we did not plan this at all. But I have a silly little thing to share about my own pickle journey. So, I used to be a pickle hater. JOËL: You know what? Same. STEPHANIE: Oh my gosh, incredible. Another new thing we've learned about each other. I really, like, wanted to like pickles because, you know, when you order a sandwich in a restaurant, it always comes with the pickle spear. And neither me nor my partner were into pickles, and we would always leave the spear uneaten on the plate, and we felt so bad about it. I felt really bad about it. And so, every, like, three to six months or so, I'd be like, okay, I'm going to gather the courage to try the pickle again and see if maybe my taste buds have changed, and this time I'll like it. And, you know, I would try a bite and just be like, no, no, I don't think it's for me. [laughs] But I guess I was just so primed to do something about, like, wanting to eliminate this really inconsequential food waste. But every time it happened, I would just, you know, [laughs] be, like, oh, if only I loved pickles. And I got my friend, who is a pickle connoisseur, to help me figure out, like, what pickles I might like. So, I asked her to come up with, like, a pickle sampler for me because I really hadn't tried all too many. And that actually really helped me find which ones were a little more palatable to me. So, I found out that I liked the sweeter ones. There's, like, a bread and butter pickle that can be quite sweet. Your diner pickle can be very different from a jar of, like, fancy pickles. [laughs] JOËL: Definitely. STEPHANIE: One day, she gifted me a jar of, like, Polish gherkins that were delicious. JOËL: Hmmm. STEPHANIE: I was like, wow, I can just snack on these. So, the thing that's new is that this time, I went to an Eastern European grocery store, and I bought my own jar of pickled gherkins. And that was something that Stephanie, like, two years ago, would never even do. [laughs] JOËL: That's really cool that you got a chance to sort of explore a broader range of what was available in the pickle world and then were able to find kind of your niche there and discover something new that you actually like. STEPHANIE: Yeah, it was very fun. And now I feel like my whole world has opened up to, you know, pickley and fermented things and just, like, get to enjoy even more snacks. So, to move away from pickles, recently, on my client project, I've been pairing a lot more with other client developers. And one thing that has come up is, you know, talking about our reasoning or our thought process for when we're pairing on some code. And I realized that I have built up a lot of either intuition or maybe some rules that I like to follow when I'm writing code, writing a test, or even doing a code review. And I've realized that you know, as developers, we often use these kinds of shortcuts or heuristics to help orient us as we're doing our work. JOËL: Yeah. I think that's definitely something that either comes yourself from experience or sometimes is passed along, and you get to benefit from somebody else's experience. They learned the hard way a lot of these tips and tricks, and now they kind of pass on some of these guidelines to us. Do you have any favorites that you reach for frequently? STEPHANIE: So, one way I like to approach a problem is to start messy [laughs] and to kind of see what that gets me and then where to go from there. I find that it's a little bit easier for me to draw on things that I've, you know, learned or picked up and tips once I have something in front of me to react to. So, maybe I will just go with the naive implementation and just write all of the code in one method, you know, in a class. And from there, now that it's out of my system, can I kind of come back in with a finer tooth comb and then apply more of a sustained effort to clean things up, right? And, to me, the question I find myself asking is, like, can this be extracted further? And so, you know, if I have everything in one giant method, then yes, [laughs] there is likely, you know, many opportunities to extract that, and maybe I will see something like, oh, the way that I spaced out this code that might be a signal to me that, like, these are some ideas that are grouped together, and I can pull something out there. JOËL: Do you have a heuristic around when to stop extracting? STEPHANIE: That's a good point. I think I tend to stop when I have kind of pulled out the classes that make sense to me. And, at that point, you know, like, maybe there is more extraction that can be done. But at a certain point, you know, you then get these really tiny classes that maybe don't hold their weight. And I think that's also true of methods that then call other methods, and that's the only thing that they do. Then it's like, well, is this too extracted that it's not really giving a future reader helpful information, right? I want the extraction to improve readability. And that tends to be another lens through which I am applying to this idea of, like, can I extract further? Is this extraction helpful for understanding this code? JOËL: I like the idea of looking at the code through multiple lenses. And so, sometimes you look at it through the lens of, yeah, are there enough moving parts here? Or does it feel kind of brittle and all in one place? And then sometimes completely shifting your lens and saying, you know what? Let's put myself in the seat of someone who's looking at this code for the first time. Can I understand it? So, structuring and extracting code is a big part of the work that we do. And I also happen to have a couple of heuristics that I like to use. One is separate branching code from doing code. So, if I have an if...else condition, I try not to put ten lines of logic inside each branch; instead, I have just a call out to a method so that the only thing the conditional does is to choose which path you go, and then each individual path is its own method. Similarly, if I'm writing a method, I'm not going to have a bunch of logic then a conditional mixed in together. So, my heuristic is a method gets to do one of two things. It either gets to choose a path to take or it gets to do a thing, but you can't mix and match both. STEPHANIE: Yeah, that makes a lot of sense. I really appreciate a well-named method that is, you know, determining, like, what condition needs to happen because then that helps me, yeah, like, avoid having to hold all of this information about this condition or this other condition, and this other condition in order to figure out what path I'm trying to take. JOËL: And the naming and the readability, I think, is a big part of this. Another heuristic that I like to use that kind of converges on the same result is trying to write each method at a single level of abstraction. So, if I am writing a method that has some kind of high-level terms it's using, I'm not going to also mix in a lot of low-level implementation. And then, similarly, if it's a method that's doing a lot of, like, low-level nuts and bolts things, I'm going to try not to pull in some of these higher-level domain name methods in there. And so, by separating things out so that every method reads one level of abstraction, you make it much easier for the reader to go through and figure out what's happening. Are we kind of getting that more 10,000-foot view, getting a sense of what's happening, and saying, okay, we want to process the user form, and then we want to send off an email, and then we want to, you know, write to a file? Or are we going through, okay, we're going to increment a counter so that we get exponential back off on our [inaudible 10:28] request? Those two things do not belong together in the same method. STEPHANIE: Yeah, absolutely. I really like this heuristic. And I have been applying it more and more and found it really useful for making sure that you're handling your errors correctly, especially because, at different levels of abstraction, you want to do different things with your errors, right? An implementation error that's raised because, you know, you're calling something accidentally on nil, or maybe a third-party service is down, and you get a custom error, whatever that is, those concerns are different from how you want to handle things at the controller level. And oftentimes, I see those things really mixed together, and honestly, I think leads to a lot of buggy code when you're trying to handle things that can go wrong at the wrong level of abstraction. JOËL: Yeah. Is there a good heuristic around what level you think is best to trigger an exception? Or maybe, more generally, just being aware of different levels of abstraction and knowing that catching or triggering errors at each level will have different impacts. STEPHANIE: I think more of the latter, the having an awareness of what kinds of errors might be possible and what impact that has on the user, right? The user being either an actual customer or, you know, another developer who has to read a notification from an error monitoring service. [laughs] JOËL: This is really interesting to me because I think we've now bridged the concept of heuristics into the idea of mental models. So, the heuristic is write your methods at a single level of abstraction, but that then leads into a mental model where maybe code is structured in three or four different layers. You've got a low level, a mid-level, a high level, something like that, of abstraction. And now, you can use that mental model to start thinking about what are the impacts of exceptions at each layer? And then, maybe you complete the circle by creating a heuristic that relies on that mental model, maybe, I don't know, raise in the low-level rescue at the top level or something. I'm making something absolutely arbitrary up right now. But somehow, we've gone from heuristic, which creates a mental model, which then allows us to build new heuristics on top of that, and that seems like a virtuous cycle to me. STEPHANIE: Yeah, absolutely. I think what I'm also picking up is the idea that you do need a mental model, or you do need to draw on your own ideas about something in order to apply the heuristic, right? You know, someone could tell you to separate branching code from doing code. But maybe you don't know what that means or, like, maybe you don't see why that's important. And sure, you can still apply it and try your best to follow it. But, in some ways, I think that the best heuristics are ones that you've kind of developed for yourself based on your own experience. JOËL: That's really interesting. I think once you've built from your own experience, I definitely feel like they're really impactful because you've kind of synthesized 2, 5, 10, 20 years of experience doing some of this work into, oftentimes, like, you know, a pithy one-line sentence, 5, 6 words that convey an approach that you've found works best, you know, maybe 80% or 90% of the time. The power of synthesis for your own self-learning I think it's really hard to understate. So, I'm curious if there's any other heuristics that you commonly use that you kind of created yourself based off your own experience rather than just having it be more of a broadly received idea from the community. STEPHANIE: I think, for me, it's more so that the experience has helped affirm certain heuristics and also made me feel more comfortable with letting others go. And one that I heard a lot but, like, didn't quite understand until really working through it deeper is the idea of feeling pain when you write a test, and that being a signal of opportunities to try different design with your code. And I just didn't know what that pain was at the beginning. Like, what does that even mean? [laughs] Like, how can a test cause me pain? But on my own, I realized, oh, like, actually, I get really frustrated when I need to stub out a whole method chain, right? And I find myself having to go look up how to do that or just spending a lot of time having to do something that I haven't done before. Maybe the pain comes from having to change a lot of files because, oh no, like, I also broke 20 other tests in the process. But when you're first starting out, oftentimes, you, like, don't know that that is not normal [laughs]; at least, that was true for me. And so, that was something that I had heard about, like, if you are feeling pain when writing a test, then, like, maybe reconsider your code design. But when you don't know how to identify what that pain is, and you also, like, don't know where to go from there, I find that, you know, the heuristic can only help you so much. JOËL: Yeah. Maybe that's something that's challenging with a heuristic in that they're often expressed as these pithy sentences. But if you're not familiar with some of the underlying concepts, that might make them harder to apply, which is unfortunate because, oftentimes, these heuristics that we've developed as a community are targeted to newcomers to help them kind of avoid the mistakes that we've made along the way. STEPHANIE: I think what really helped me the most in connecting a heuristic that's commonly expressed and my own experience is when I've had someone ask me about how I'm feeling when I'm, you know, making some kind of decision or when I'm reading some code. Like, what do I think of this, or what has been my experience with this? And giving me the opportunity on the spot to synthesize that information. Because otherwise, it's hard to figure out, you know, like, what is just normal? This is just life as a developer [laughs]. And what are opportunities to maybe gain some more insight about the work itself? JOËL: One thing that I've learned over time as a developer, and I'm not sure if this quite rises to the level of a heuristic, but a lot of, like, pain and frustration in development doesn't necessarily have to be that way. And it's not necessarily because I'm bad at the job or I'm too new to the technology or whatever. It can often be a sign of underlying design issues or the fact that the system was modeled with certain assumptions that are no longer true. These can often be signals that you can make things better. So, I think if I had to reduce this idea down to a clever one-liner, it'd be something along the lines of, it can be better, or it doesn't have to be this bad. You're writing a test, and it's really annoying. There might be a better way to structure the underlying code that would make the test better. You're having to do some, like, really clunky code to deal with something. Is there maybe a better object design that would make a lot of that pain go away, or at least kind of quarantine it in a certain part of the codebase? STEPHANIE: I actually think you're really onto something because what I was just hearing, I love that, like, it can be better. It's less prescribed, I guess, than some other heuristics, like, you know, do not repeat yourself, or whatever. JOËL: Classic. STEPHANIE: [laughs] It really encourages, like, the individual to think a little deeper. And it actually reminded me of another...this is actually a bit of a pithy saying, but I find it to be really useful. And I'm curious if you've heard it before. It's a systems thinking heuristic, and the phrase is, the purpose of a system is what it does. JOËL: Ooh, I have heard that, and I'm trying to remember what context. STEPHANIE: So, it was coined by a systems thinking expert. Stafford Beer, I think, is his name. And I recently learned about it from a friend. But I think the cool thing is that it can be applied to literally anything [laughs] because everything is a system, you know, or not just software. But I have found a lot of value in applying it to just, like, is this function doing what it says it does, right? Or is it actually also doing, like, a side effect? And turns out, maybe we want to bring that into alignment with what the name of the function is, or try pulling that out, or whatever. I think it can also be true of test suites. I don't know if this is a heuristic or not. But the idea that we should always be testing or all tests are good, yeah, I guess that could pass as a heuristic. By bringing this perspective of the purpose of a system is what it does, it's like, well, is the test suite also so bloated and takes so long and so flaky that it is actually hindering development? And if that is the case, then maybe there is some reevaluation necessary, right? Rather than just claiming that it's helping us have more confidence in our code when that may or may not be true. JOËL: You brought up an interesting idea here, which is that heuristics aren't always right. So, you're talking about the idea that a heuristic like good code is tested code might not be correct in 100% of the cases. Like, how accurate does a heuristic need to be in order for it to be really valuable? You know, you're hoping for something that's, like, 90% correct that you can follow most of the time, except in some edge cases, or something maybe as low as, like, 50% where it's a coin toss whether the heuristic applies in the situation or not. Are those still useful? Or are they maybe more confusing than otherwise? STEPHANIE: Oh wow. That's a really interesting way to frame it because I don't know if I've ever stored information about how well my heuristics are serving me. [laughs] But I do really like the idea that you can use a heuristic as a guiding principle just to try and that you can always back out of it, right? So, if you're wanting to take DRY to the extremist of extremes, just for fun or just to see how that might go, you can go down that path and, at any point, decide, okay, like, I like this, or I don't like this, and choose a different path. But the idea of kind of tracking, like, how well they're working for you that is really interesting to me, and not something I've tried before. JOËL: I love the idea of taking a heuristic and, like, doing a side project whose whole goal is just to kind of push that heuristic to the extreme, to the breaking point so that, that way, you get an intuition of, like, when does it work for you? When does it not? That sounds like a really fun exercise for someone to do. Is that something that you've done yourself? STEPHANIE: Not to the point of a whole side project, but just like I like to try pickles randomly every now and then to see if I like them, [laughs] will just try a new technique and see how it goes. In an episode a while back, we talked about whether we TDD or not, and, to be honest, I don't do it, you know, 100% of the time or all the time. But one day, I did decide to TDD a full-stack feature from start to finish just for fun [laughs], and I enjoyed it. I learned some things about it. And I think now I've kind of integrated the parts that I liked about it into my development flow. Like, I'm not always going to do it. But I think it also just helped me figure out, like, okay, like, what is this thing about that people claim that is the pinnacle of how we should be writing our code? And how can I decide for myself, like, whether it works for me or just pick and choose the parts of it that work for me? JOËL: Yeah. That just seems like a really valuable exercise. There are definitely too many heuristics out there to do that for everything. But I guess I've never thought of it quite so concretely. But I almost wonder if I should, like, add this to my kind of personal growth plan to say, like, once a year, I'm going to take a heuristic and kind of push it to an extreme and see what I can learn about it. STEPHANIE: I actually think what's really cool is the process of, like, any individual developer figuring out what kinds of heuristics they want to follow, as opposed to, you know, like, a mass proclamation that, like, this is the way, right? Are there any heuristics that you have maybe picked up and then let go of because you realized that, you know, they weren't working enough or frequently enough for you or that you just didn't like? JOËL: I don't know about, like, fully letting go, but definitely kind of recontextualize and sometimes even sort of rewrote them a little bit to work for me. So, a classic one would be the idea that shorter code is more readable. So, it's common to see comments on a pull request sort of like, "Hey, you could make this shorter by doing this." And that can be true to a certain extent. When you get to the point where you're playing code golf, it becomes absolutely unreadable. But also, there's a point where sometimes using some other heuristics will result in longer code but actually make it more readable on the whole. And so, packing everything into one method might be overall shorter, so it's fewer lines to read going through a class. But maybe extracting some methods or doing that separating branching code from doing code might lead to an overall longer class but an also overall more readable one. So, I think there's probably a lot of caveats that go with that idea. Oftentimes, shorter can be more readable with, you know, two or three asterisks that maybe go a little bit more into the why that is the case. STEPHANIE: Yeah. I like the contextualizing. That actually reminded me of a talk that I watched recently by Hillel Wayne. It's called Intro to Empirical Software Engineering. And he basically, like, does a deep dive into all these studies about software practices that we think are, quote, unquote, "good," like, as a community or as an industry. And it's like, well, like, how do we actually know? Like, show me the research, right? And one of the studies that he included was trying to determine if using abbreviations for variable names or using the full words made the code easier to debug or not. And so, the main example that he was using was employee number as a variable, and the abbreviation was EMP num. And it turns out that there was no difference in how easy it was to debug. But the approach that each group that was studied differed. So, the folks who had the full names, the full words for the variable names, were kind of using an approach of just scanning the code and being able to understand at a higher level the domain, right? Whereas the folks who were debugging with just abbreviations had to work at a bit of a lower level and, you know, or maybe using breakpoints and debugging the code that way. And I thought that was really cool because, first of all, I think it kind of was trying to prove that, like, we don't actually know if one is better or not. But what is important and interesting to me is the idea that, like, you can choose the method that you like better or that works for you and the human side of it, right? The impact it has on our process. JOËL: That's really cool. I'll have to go and watch that talk. Building this kind of context and nuance around a heuristic, though, takes a lot of time, takes experience. And part of the value of a heuristic is that we're collapsing down maybe our own experience or somebody else's experience into something that doesn't require you to necessarily do all that work upfront. How do you feel about sharing and kind of targeting a lot of these heuristics to newer coders who are kind of trying to get better at their craft and looking for ways to improve without necessarily having to do, you know, five years of experience digging into a particular topic? Do you think heuristics are helpful, or do they maybe mislead? STEPHANIE: I really value when they're presented as an opinion, as opposed to a true fact about code. [laughs] Because I really appreciate when someone is able to explain to me why they chose readability in this particular scenario or why they chose speed and performance. Or maybe they were making a trade-off between accessibility and, you know, something else. To just, like, tell someone, "Oh yeah, like, DRY code is better code," or to just tell someone that without the explanation with, like, offering them the opportunity to reflect themselves on, like, oh, like, where have I seen DRY code that was easier for me to read? That seems a little less helpful in terms of investing in their growth. JOËL: Yeah. Definitely, I think sharing some of the purpose behind it can often be really useful because most of these heuristics are never an end unto themselves. They're a means to some other end. So, you're not writing code that's DRY just because you want to be cool. You're writing code to be DRY because you're trying to improve readability, make it easier to change so you don't have to change it in multiple places. You want to maybe reduce the chance of certain types of bugs. These are all actual purposes of what you want to do in your code. DRY is just one way of getting there. But oftentimes, we might skip that part and just be like, hey, you should make your code DRY because DRY is the best. And it can be, but it's in service to these other goals. STEPHANIE: I think when I am sharing those types of heuristics that are more commonly held, I also do like to preface, like, some people think this, or some people like to do things this way, just to be clear that they don't have to like it or do it. In general, I always prefer injecting more nuance [laughs] into the conversation. But yeah, like, it is a really personal process, I think, and figuring out, like, how any individual makes decisions about, like, all the code they're writing. You have to make a million [laughs] decisions every time you do it. So, yes, like, those heuristics do provide a shortcut. And also, I think it's worth taking the time to think about if it's working, especially for the specific context that you're applying it, right? Because that also can change. And, I don't know, maybe I'm just skeptical of any one size fits all solution. JOËL: I think for myself, with many heuristics, as a beginner coder, I had a bit of, like, a spiral journey, or maybe kind of going up a set of stairs. So, as a brand-new developer, I would make a lot of duplication bugs in my code, where, you know, I would have the same value in multiple places, and then I'd change it in one place, and I don't remember to change it in other places, and the code breaks. And so, being introduced to the idea of DRY actually helped my code get quite a bit better. It was, like, a net positive on my experience because I was not getting burned by all these bugs quite so frequently. And so, for a while, just throwing more DRY into my code just made my life better. And then, eventually, you kind of hit that plateau where I don't run into the pain of these bugs anymore. But now I keep doing more DRY somewhat mindlessly. And I end up with this pile of abstractions that are actually really brittle or frustrating to work with. And now, I have to rethink some of the assumptions behind the heuristic. And then, at that point, yep, maybe recontextualize a little bit, learn about when it's good, when are the trade-offs not worth it. Now I have a better understanding, and I kind of go on another growth bit where it makes a lot of my code better until maybe I hit another plateau. I've kind of maxed out the benefits. I start seeing some of the pain, and then, again, I have to go through this cycle again. And maybe the approach you were talking about earlier, where you do a side project and kind of push a heuristic to its breaking point, is a way to kind of speed run that process. STEPHANIE: Yeah, that's really interesting because you're just committing to it and trying to learn everything you can from it in a very concentrated setting. I also wonder, and it's totally fine if you don't know, but if someone had told you kind of all of those reasons you listed about why DRY code, like, what that achieves, if that may have reframed how you were thinking about applying it. Or was that also something that had to come from doing it enough? JOËL: I think as a brand-new developer, a lot of that would have gone over my head. I was still really shaky on the concept of abstraction. When is it useful? When is it not? So, a lot of those more subtle pitfalls, I think, would not have been relevant to me at that point in my career, even the concept of readability, right? When I'm a brand-new programmer, I'm still getting used to reading a lot of code. And so, the idea that code might be written in a way that's unreadable or more challenging to read, it might just feel like, oh, I just need to get better, improve myself. It's not that the code is written in a hard-to-read way. It's just I don't have enough experience at reading code. And I think that's a common thing that we do as beginners at everything, right? We start by blaming ourselves when things get hard. STEPHANIE: Yeah. I was just thinking that, you know, if you are sharing heuristics with a newer developer or an early-career developer, at the end of the day, like, really, I'm not sure about the value of just dropping it on them and letting them run [laughs] with it. But I think what could be really, really effective is just having a sustained relationship with them and, like, continuing that conversation. It's, like, maybe in a code review or in a pairing session being like, "Oh yeah, like, I see you're practicing DRY. Like, what do you think about how this made this piece of code different?" And kind of baking in that process of self-discovery along the way and speeding it up in that way as well. JOËL: So, what you're really saying is the one heuristic to rule them all is code in community. STEPHANIE: I love that. I'm totally with you. JOËL: On that note, shall we wrap up? STEPHANIE: Let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeee!!!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
Stephanie is consciously trying to make meetings better for herself by limiting distractions. A few episodes ago, Joël talked about a frustrating bug he was chasing down and couldn't get closure on, so he had to move on. This week, that bug popped up again and he chased it down! AND he got to use binary search to find its source–which was pretty cool! Together, Stephanie and Joël discuss dependency graphs as a mental model, and while they apply to code, they also help when it comes to planning tasks and systems. They talk about coupling, cycles, re-structuring, and visualizations. Ruby Graph Library (https://github.com/monora/rgl) Graphviz (https://graphviz.org/) Using a Dependency Graph to Visualize RSpec let (https://thoughtbot.com/blog/using-a-dependency-graph-to-visualize-rspec-let) Mermaid.js (https://mermaid.js.org/) Strangler Fig pattern (https://martinfowler.com/bliki/StranglerFigApplication.html) Transcript: JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. STEPHANIE: And I'm Stephanie Minn. And together, we're here to share a bit of what we've learned along the way. JOËL: So, Stephanie, what's new in your world? STEPHANIE: So, I'm always trying to make meetings better for me [chuckles], more tolerable or more enjoyable. And in meetings a lot, I find myself getting distracted when I don't necessarily want to be. You know, oftentimes, I really do want to try to pay attention to just what I'm doing in that meeting in the moment. In fact, just now, I was thinking about the little tidbit I had shared on a previous episode about priorities, where really, you know, you can only have one priority [laughs] at a time. And so, in that moment, hopefully, my priority is the meeting that I'm in. But, you know, I find myself, like, accidentally opening Slack or, like, oh, was I running the test suite just a few minutes before the meeting started? Let me just go check on that really quick. And, oh no, there's a failure, oh God, that red is really, you know, drawing my eye. And, like, could I just debug it really quick and get that satisfying green so then I can pay attention to the meeting? And so on and so forth. I'm sure I'm not alone in this [laughs]. And I end up not giving the meeting my full attention, even though I want to be, even though I should be. So, one thing that I started doing about a year ago is origami. [laughs] And that ended up being a thing that I would do with my hands during meetings so that I wasn't using my mouse, using my keyboard, and just, like, looking at other stuff in the remote meeting world that I live in. So, I started with paper stars, made many, many paper stars, [laughs] and then, I graduated to paper cranes. [laughs] And so, that's been my origami craft of choice lately. Then now, I have little cranes everywhere around the house. I've kind of created a little paper crane army. [laughs] And my partner has enjoyed putting them in random places around the house for me [laughs] to find. So, maybe I'll open a cabinet, and suddenly, [laughs] a paper crane is just there. And I think I realized that I've actually gotten quite good at doing these crafts. And it's been interesting to kind of be putting in the hours of doing this craft but also not be investing time, like, outside of meetings. And I'm finding that I'm getting better at this thing, so that seemed pretty cool. And it is mindless enough that I'm mentally just paying attention but, yeah, like, building that muscle memory to perfecting the craft of origami. JOËL: I'm curious, for your army of paper cranes, is there a standard size that you make, or do you have, like, a variety of sizes? STEPHANIE: I have this huge stack of, like, 500 sheets of origami paper that are all the same size. So, they're all about, let's say, two or three inches large. But I think the tiny ones I've seen, really small paper cranes, maybe that would be, like, the next level to tackle because working with smaller paper seems, you know, even more challenging. JOËL: I'd imagine the ratio of, like, paper thickness to the size of the thing that you're making is different. STEPHANIE: At this point, they say that if you make 1,000, then you bring good luck. I think I'm well on my way [laughs] to hopefully being blessed with good luck in this household of my little paper crane army. JOËL: It's interesting that you mentioned the power of having something tactile to do with your hands during a meeting, and I definitely relate to that. I feel like it's so easy, even, like, mindlessly, to just hit Command-Tab when I'm doing things on a screen. Like, my hands are on the keyboard. If I'm not doing something, I'm just going to mindlessly hit Command-Tab. It's kind of like on your phone sometimes. I don't know if you do this, like, just scrolling side to side. You're not actually doing anything. You just want motion with your fingers. STEPHANIE: Yes. I know exactly what you're talking about. And it's funny because it's a bit of a duality where, you know, when you are in your development workflow, you want things to be as quick and convenient as possible, so that Command-Tab, you know, is very easy. It's just built in, and that helps speed up your, you know, day-to-day work. But then it's also that little bit of mindlessness, I think, that can get you down the distraction path. When I was first looking for something to do with my hands, to have, like, a little tactile thing to keep me focused in meetings, I did explore getting one of those fidget cubes; I have to say. [laughs] It's just a little toy, you know, that comes with a bunch of different settings for you to fidget with. There's, like, a ball you can roll, you know, with your thumb, or maybe some buttons to click, and it gives you that really satisfying tactile experience. And I know they work really well for a lot of people, but I've really enjoyed the, I guess, the unexpected benefits [chuckles] of getting better at a hobby [laughs] while spending my time at my work. Joël, what is new with you? JOËL: So, a few episodes ago, I talked about a really kind of frustrating bug that I was chasing down that was due to some, like, non-determinism in the environment. And it kind of came, and then it went away. And I wasn't able to get sort of closure on that and had to move on. Well, this week, that bug popped up again, and this time, I was actually able to chase it down. So, that felt really exciting. And I got to use binary search to try to find the source of it, which made me feel really cool. STEPHANIE: Oooh, do tell. What ended up being the issue? JOËL: I'm connecting to an external Snowflake data warehouse, and ActiveRecord tries to fetch the schema and crashes as part of that with some cryptic error that originates from the C extension ODBC Ruby driver package. I figured out that it's probably something to do with, like, a particular table name or something in the table metadata when we're pulling this schema that we're not happy about. But I don't know which table is the one that it's not happy with. Well, this time, I was able to figure out, by reading through some of the documentation, that I can pull subsets of the schema. So, I can pull the first n values of that schema, and it won't crash. It only crashes if I try to fetch the entire set, which is what is happening under the hood. At that point, you know, I could fetch each row individually, but there's hundreds of these. So, you know, I try, okay, what happens if I try to fetch 1,000 of these? Is it going to crash? Because it's a massive system. So, yes, I get a crash. So, I know that a table less than a thousandth in the list of tables is what's causing the problems. So, okay, fetch 500 halfway in between there. It's still going to crash. Okay, 250, 125. I then kind of keep halving all the time until I find one that doesn't crash. And now I know that it is somewhere between the last crash and this one. So, I think it was between 125 and 250. And now I can say, okay, well, let's fetch the first, you know, maybe 200 tables, okay, that crashes. And I keep halving that space until you finally find it. And then, like, okay, so it's this one right here. Now, the problem is the bad table actually crashes. So, I think it ended up being, like, number 175 or something like that. So, I never get to see the actual table itself. But because the list of tables is in alphabetical order, and I can see because I can fetch the first 174 and it succeeds, so I can tell what the previous 5, 6, you know, previous 174 are. I can pretty easily go and look at the actual database and the list of tables and say, okay, well, it's in the same order. And the next one is this one, and hey, look, there is some metadata there that has some very long fields that are longer than one might expect, specifically going over a potentially implied 256-character limit. That seems somewhat suspicious. And, oh, if we remove this table, all of a sudden, everything works. STEPHANIE: Wow, binary search, an excellent debugging tool [laughs] when you have no idea, you know, what could possibly be causing your issue. JOËL: It's such a cool tool. Like, I'm always so happy when I get a chance to use it. The problem is, you need a way to be able to answer the question, like, have I found it? Yes or no? Or, generally, is it greater or less than this current position? STEPHANIE: Well, that's really exciting that you ended up figuring out how to solve the bug. I know last time we talked about it, you kind of had left off in a space of, hopefully, we won't run into this issue again because it's no longer happening. But it seems like you were also set up this time around to be able to debug once it cropped up again. JOËL: Yes. So, binary search is really cool. It's got this, like, very, like, fancy computer science name. But in reality, it's a fairly simple, straightforward technique that I use fairly frequently in my development. And there's another kind of computer sciency fancy-sounding concept that I use all the time. You've all heard me reference this multiple times on the show. You're right; we're finally doing it. This is the dependency graph episode. STEPHANIE: Woo. [laughter] It's time. I'm excited to really dig into it because, you know, as someone who has heard you talk about it a lot, you know, and is maybe a little less familiar with graph theory and how, you know, it can be applied to my day to day work, I'm really excited to dig into a little bit about, you know, what a regular developer needs to know about dependency graphs to add to their toolbox of skills. JOËL: So, I think at its core, the idea of a dependency graph is that you have a group of entities, some of which depend on each other. They can't do a task, or they can't be created unless some other subtasks or dependent actions take place. And so, we have a sort of formal structural way of describing these things. Visually, we often draw these things out where each of the pieces is like a little bubble or a circle, and then we draw arrows towards the things that it depends on. So, if A cannot be done without B being done first, we draw an arrow from A to B. That's kind of how it is in the abstract. More concretely, this kind of thing shows up constantly throughout the work that we do because a lot of what we do as developers is managing things that are connected to each other or that depend on each other. We build complex systems out of smaller components that all rely on each other. STEPHANIE: Yeah, I think it's interesting because I use the word dependency, you know, very frequently when talking about normal work that I'm doing, you know, dependencies as in libraries, right? That we've pulled into our application, or dependencies, like, talking about other classes that are referenced in this class that I'm working in. And I never really thought about what could be explored further or, like, what could be learned from really digging into those connections. JOËL: It's a really powerful mental model. And, like you said, dependencies exist all over our work, and we often use that word. So, you mentioned something like packages, where your application depends on Rails, which in turn depends on ActiveRecord, which in turn depends on a bunch of other things. And so, you've got this whole chain of maybe immediate dependencies, and then those dependencies have dependencies, and those dependencies have dependencies, and it kind of, like, grows outward from there. And in a very kind of simplistic model, you might think, oh, well, it's more, like, a kind of a tree structure. But oftentimes, you'll have things like branches on one side that connect back to branches on the other. And now you've got something that's no longer really tree-like. It's more of a sort of interconnected web, and that is a graph. STEPHANIE: I think understanding the dependencies of your system has also become more important to me as I learn about things that can go wrong when I don't know enough about what my system is, you know, relying on that I had kind of taken for granted previously. I'm especially thinking about packages like we were mentioning, and, you know, not realizing that your application is dependent on this other library, right? That's brought in by a gem that you're using. And there's maybe, like, a security issue, right? With that. And suddenly, you have this problem on your hands that you didn't realize before. And I know that that has been more of a common discussion now in terms of security practices, just being more aware of all the things that you are depending on as really our work becomes more and more interconnected with the things available to us with open source. JOËL: I think where understanding the graph-like nature of this becomes really important is when you're doing something like an upgrade. So, let's say you do have a gem that has a security problem, and you want to upgrade it to fix that security issue. But the upgrade that includes the security patch is also a breaking upgrade. And so, now everything else in your system that depends on that gem or on that package is going to break unless you have them in a version that is compatible with the new version of that gem. And so, you might have to then go downstream and upgrade those packages in a way that's compatible with your app before you can bring in the security patch. And a lot of that can be done automatically by Bundler. Bundler is software that is built around navigating dependency graphs like that and finding versions that are compatible with each other. But sometimes, your code will need to change in order to upgrade one of these downstream gems so that you can then pull in the upgrade from the gem that needs a security patch. And so, understanding a little bit of that graph is going to be important to safely upgrading that gem. STEPHANIE: So, I know another application of dependency graphs that you have thought about and written a blog post for is RSpec let declarations and how a lot of the time when we are using let, you know, we are likely calling other variables defined by let. And so, when you are encountering a test file, it can be really hard to grok what data is being set up in your test. JOËL: Yeah, so that is really interesting because you can define something that will get executed in a lazy fashion if it gets referenced. But then not only is the let lazy and will not trigger unless it's referenced, but a let can reference other lets, which are also lazy, and only get triggered if they get referenced. So, you might have a bunch of lets defined in any order you want throughout a file, and they're all kind of interconnected with these references to each other. But they only get triggered if something calls it directly or it's in this, like, chain of dependencies. And getting a grasp on what actually gets created, which lets will actually execute, which ones don't in a file can quickly get out of hand. And so, thinking of this in terms of a dependency graph has been a really helpful mental model for me to understand what's going on in a complex test file. STEPHANIE: Yeah, absolutely. Especially when sometimes the lets are coming from all over the place, you know, maybe a describe block hundreds of lines away, or even a completely different file if you are using a shared context that's being pulled in. So, I can see why this was a complex problem that could be made a little simpler with plotting out a dependency graph. And in preparation for this episode, I was doing a little bit of my own exploration on this because I certainly know, you know, the pain of trying to figure out what is being executed in my tests when there are a lot of lets that reference each other. And in the blog post, you kind of gave a little step-by-step of how you could start with creating a dependency graph for the test that you're working with. And I was really curious if this process could be automated because, you know, I do enjoy, you know, pulling out the pen and paper [chuckles] every now and then. But I'm not, like, a particularly visual person. God forbid I, like, draw a circle, but then, like, don't have enough space for the rest of the circles. [laughs] So, I was really hoping for a tool that could do this for me, especially if, you know, you do, you have a lot of tests that you have to try to understand in a relatively short amount of time. And so, I ended up doing something kind of hacky with RSpec and overriding let definitions to automate this process. JOËL: That's really cool. So, is the tool that you're trying to build something where you feed it in a spec file, and it gives you some kind of graphical representation like an SVG or something as output? STEPHANIE: Yeah. I did consider that approach first, where you feed in the file, but then I ended up going with something more dynamic where you are running the test, and then as it gets executed, tracing the let definitions and then registering them to build your dependency graph. JOËL: So, you've got some sort of internal modeling that describes a dependency graph. And then, somehow, you're going to turn that, you know, a series of Ruby objects into some kind of visual. STEPHANIE: Yeah, exactly. And the bulk of that work was actually done with a library called RGL, which stands for just Ruby Graph Library. [laughs] And what's nice is that it has a really easy interface for plugging in the vertices and edges of the dependency graph that you want to build. And then, it is already hooked up with Graphviz to, you know, write the SVG to a file. And so, I ended up really just having to build up an array of my dependencies and the connections to each other and then feed it into the constructor of the graph. JOËL: And for all of our listeners, you mentioned Graphviz. That is a third-party tool that can be installed on your machine that can generate these SVG diagrams from...I believe it has its own sort of syntax. So, you create, I believe it's dot, D-O-T, so dot dot file. And based off of that, it generates all sorts of things, but SVG being potentially one of them. STEPHANIE: Yeah. The nice thing was that I actually didn't end up having to use the DSL of Graphviz because the RGL gem was doing them for me. JOËL: Nice. So, it plugs in directly. STEPHANIE: Yeah, exactly. And I was really curious about using this gem because I, you know, just wanted to write Ruby, especially to plug into other things that are already in Ruby. And I found that surprisingly easy, thanks to all of the RSpec config options that they make available to you, including an option to extend the example group class, which is actually where let and let bang is defined. And so, I ended up overriding those classes and using, you know, the name of the let that you're defining and then the block to basically register the dependencies. And I also ended up exploring a little bit with using Ruby's built-in parser to figure out in the block that's being passed to the let, what parts of that block could potentially be a reference to another let. JOËL: That's really cool. Did you get any fun results from that? STEPHANIE: I did. It worked pretty well in being able to capture all of the let declarations, and other lets that it references. And so, I was able to successfully, you know, like, generate a visual dependency graph of all of the lets, so that was really neat. The part that I was really kind of excited about trying next, though I didn't end up having time to yet, was figuring out which of those let values are executed by way of the let bang, right? Which is eager or what is referenced in the test that then gets executed as well. And so, the RGL library is pretty neat and has some formatting options, too, with the Graphviz output. So, you can change the font color or styling options for different, you know, nodes and edges. And so, I was really curious to pursue this further, maybe, and use it to show exactly what gets evaluated now that I have successfully mapped my let graph. JOËL: Right. Because the whole point of this exercise is that not the entire graph is going to get evaluated. The underlying question is, what data actually gets created when my test runs? And so, you build out this whole dependency graph, and then you can follow a few simple rules to say, okay, this branch gets called, this branch gets called, this series of things gets called. And okay, this subset of let blocks trigger, and therefore this data has been created for my given test. STEPHANIE: Yeah. Though I will say that even where I got so far to, just seeing all of the let definitions in a spec file was really helpful to have a better understanding, you know, if I do have to add a test in here, and I'm thinking about reaching for a pre-existing let declaration, to be like, oh, like, it actually, you know, goes on to reference all of these other things that may be factories [chuckles] that are created might make me, you know, think twice, or just have a little better understanding of what I'm really dealing with. JOËL: Right. The idea that when you're calling out to a let, or a factory, or something else that's just a node in a large graph, you're not necessarily referencing just one thing. You might actually be referencing the head of a very long chain of things that maybe you don't intend to trigger the whole thing. STEPHANIE: Yeah, exactly. JOËL: So, in that sense, having a sort of visual or at least an idea of the graph can give you a much better sense of the cost of certain operations that you might have to do. STEPHANIE: The cost of the operations certainly, especially when, you know, you are working in a legacy codebase, and you, you know, like, maybe don't know how everything plays together or is connected. And it's very tempting to just reach for [chuckles] the things that have been, you know, created or built for you. And I'm certainly guilty of that sometimes on this client project, where the domain is so complex, and there are so many associated models. And I'm like, well, like, let me just, you know, use this let that already, you know, has a factory set up for what I think I need for this test. But then realizing, oh, actually, like, it is creating all these things, and do I really need them? I think it can be really challenging to unravel all of that in your head. And so, with this very scrappy tool that I [chuckles] built for my own purposes, you know, maybe it makes it, like, one step easier to try to fully understand what I'm working with and maybe do something different. JOËL: One aspect that I think is really powerful about dependency graphs is that it takes this kind of, like, abstract concept that we oftentimes have an intuitive sense around, the idea that we have different components that depend on each other, and it shows it to us visually on, like, a 2D plane. And that can be really helpful to get an understanding or an overview of a system. You mentioned that RGL uses Graphviz to generate some SVGs. A visual tool that I've been using to draw some of my dependency graphs has been mermaid.js. It has a syntax that's, like, a text-based syntax, but it's almost visual in that you have a piece of text and name of a node. And then, you'll draw a little ASCII arrow, you know, two dashes and a greater than sign to say this thing depends on, and then write another name, and just have a row, like, a bunch of entries to say; A depends on B. A also depends on C. C depends on D, and so on, and, like, build up that list. And then Mermaid will just generate that diagram for you. STEPHANIE: Yeah. I've used Mermaid a few times. One really helpful use that I had for it was diagramming out a bunch of React components that I had and wanting to understand the connections between them. And I think you can even paste the Mermaid syntax into your GitHub pull request description, and it'll render as the graph image. JOËL: Yeah, that's what's really cool is that Mermaid syntax has become embedded in a lot of other places in the past few years. So, it's really easy to embed graphs now into all sorts of things. You mentioned GitHub. It works in pull requests descriptions, comments, I think pretty much anywhere that Markdown is accepted. So, you could put one in your README if you wanted. Another place that I use a lot, Obsidian, my note-taking tool, allows me to embed graphs directly in there, which is really much nicer than previously; sometimes, when I wanted to express something as a visual, I would use some sort of drawing tool to do something and export an image, and then embed that in my note. But now I can just put in this text, and it will automatically render that as a diagram. And part of what's really nice about that is that then it's really easy for me to go and change that if I'm like, oh, but actually, I want to add one more connection in here. I don't have to re go back to, hopefully, a file that I've saved somewhere and, like, change an image file and re-export it. I just, you know, I add one line of text to my note, and it just works. STEPHANIE: That's awesome. Yeah, the ability to change it seems really useful. So, we've talked a little bit about tools for creating a visual aid for understanding our dependencies. And now that we have our graph, maybe we might have some concerning observations about what we see, especially when perhaps some of our dependencies are pointing back to each other. JOËL: Yes. So, I think you're referencing cycles, in particular. That would be the formal term for it. And those are really interesting. They happen in dependency graphs. And I would say, in many cases, they can be a bit of a smell. There's definitely situations where they're fine. But there are things that you look at, and you're like, okay, this is going to be a more complex kind of tricky bit of the graph to work with. Some cases, you just straight up can't have them. So, I want to say that the way RSpec lets are set up, you cannot write code that produces cycles. But you might have...I think Ruby allows classes to reference each other in such a way that it creates a cycle, and not all languages do that. So, Elm and F#, I believe, require that modules cannot reference each other. The fancy term for this is a dependent acyclic graph, or DAG, which basically just means that there are no cycles in that graph. STEPHANIE: Yeah. What you said about classes referencing each other is very interesting because I've definitely seen that. And then, if I have to go about changing something, maybe even it's just the class name, right? Now there's no way in which I can really make just one change. I have to kind of do it all in one go. JOËL: I think that's a common property of a cycle, and a graph is that changes that happen somewhere in that cycle often need to be all shipped together as one piece. You can't break it up into smaller chunks because everything depends on everything else. So, it has to be kind of boxed together and shipped as one thing. STEPHANIE: And you'd mentioned that cycles, you know, can be a bit of a code smell. And if the goal is to be able to break it up so that it is a little bit more manageable to work with, how would you go about breaking a cycle? JOËL: So, I think breaking a cycle is going to vary a little bit based on your problem domain. So, are you modeling a series of classes that are referencing each other? Is this a function call graph? Is this even, like, a series of tasks that you're trying to do? But typically, what you want to do is make sure that eventually, at some point, like, something doesn't loop back to referencing something higher up in your hierarchy. And so, oftentimes, it ends up being about what is allowed to know about what? Do you have higher-level concepts that can know and depend on lower-level concepts but not vice versa? And again, we are talking about this a little bit at the abstract level. But in terms of, let's say, different code modules, or classes, or something like that, commonly, you might say, well, we want some sort of layering where we have almost, like, more primitive types of classes at the bottom. And they don't get to know about anything above them. But the ones above that might be more complex that are composed of smaller pieces know about the ones below them. And you might have multiple layers kind of like that that all kind of point down, but nothing points up. STEPHANIE: That is a very common heuristic. [chuckles] I think you were basically just describing how I also understand creating React components, where you want to separate your presentational ones from your functional ones. And, yeah, it makes a lot of sense that as soon as you start adding that complexity of, you know, those primitive classes at the bottom, starting to, you know, point to things higher up or to know about things higher up, that is where a cycle may be accidentally introduced. JOËL: It's interesting just how many design principles that we have in software. If you dig into them a little bit, you find out that they're about decoupling things, and oftentimes, it's specifically breaking up cycles. So, one way that you might have something like this that actually has dependency in the name, the dependency inversion principle, where what you're effectively doing is you're taking one of those dependency arrows, and you're flipping it the other way. So, instead of A depending on B, you're flipping it. Now B depends on A, and that can be enough to break a cycle. STEPHANIE: So, one thing I've picked up from our conversations about dependency graphs is that oftentimes, you know, when you're trying to figure out where to start, you want to look for those areas or those nodes where there's nothing else that depends on it. JOËL: Yeah. I think you have those nodes that, if this were a tree, you would call them the leaf nodes. In the case of a graph, I'm not sure if that's technically correct, but they don't depend on anything. They're kind of your base case. And so, you can, you know, if it's a function, you can run it. If it's a file, you can load it; if it's a class, also you can load it up and not have to do anything else because it has no dependencies. And knowing that those are there, I think, can be really useful in terms of knowing an order you might want to execute something in. And this is really interesting for one of my favorite uses of a graph, which is breaking down a series of tasks that you need to do. So, commonly, you might say, okay, I have a large task I need to do. I break it down into a series of subtasks. And, you know, maybe I draw out, like, a bulleted list and, you know, task 1, 2, 3, 4, 5. The problem is that they're not necessarily just a flat list. They all have, like, orders, like dependencies between each other. So, maybe one has to happen before 2, but it also has to happen before 3, which needs to happen before two, and, like, there's all these interconnections. And then, you find out that you can't ship them independently the way you thought initially. So, by building up a graph, you end up with something that shows you exactly what depends on what. And then, like you said, the parts that are really interesting where you can start doing work are the ones that have no dependencies themselves. Other things might depend on them, but they have no dependencies. Therefore, they can be safely built, shipped, deployed to production, and they can be done independently of the other subtasks. STEPHANIE: Yeah. I was also thinking about things that could be done in parallel as well. So, if you do have multiple of those items with no dependencies, like, that is a really good way to be able to break up that work and, yeah, identify things that are not blocked. JOËL: For a complex set of tasks, it's great to see, okay, these two pieces have no dependencies. We can have them be done in parallel, shipped independently. And then you can just kind of keep repeating that process. Because once all of the tasks that have no dependencies have been done, well, you can almost, like, remove them from the graph and see, okay, what's the new set of things that have no dependencies? And then, keep doing that until you've eventually done the whole graph. And that may sound like, oh okay, we're just kind of using a little bit of intuition and working through the graph. It turns out that this is a, like, actual, like, formal thing. When it comes to graphs, it's a traversal algorithm called topological sort is the fancy name for it, and it basically, yeah, it goes through that. It gives you a list of nodes in order where each node that you're given has no dependencies that have not been evaluated yet. So, it works from effectively to use our tree terminology, from the leaf nodes to the root, potentially roots plural, of the graph, and each step is independent. So that's a lot of, like, fancy terminology, and getting a little bit of, like, computer science graph theory into here. So, my, like, general heuristic is that graphs should be evaluated from the bottom up when you're trying to evaluate each piece independently. So, when you do that, you get to do each piece independently, as opposed to if you're evaluating from the top down. So, starting from the one thing that depends on everything else, well, it can't be shipped until all of its dependencies have been shipped. And all the transitional dependencies can't be shipped until their dependencies have been shipped. And so, you end up being not able to ship anything until you've built the entire graph. And that's when you end up with, you know, a 2,000-line PR that took you multiple weeks and might be buggy. And it's going to take a long time to review. And it's just not what anybody wants. STEPHANIE: I'm glad you brought this up because I think this is where I am really curious to get better at because oftentimes, when I am breaking down a complex task, it's quite hard for me to see all of the steps that need to happen. And so, you know, you maybe start out with that, like, top-level node, like, the task that needs to be done as you understand it immediately. And it's really hard to actually identify the dependencies and, like, the smaller pieces along the way. And because you're not able to identify that, you think that you do have to just do it all in one go. JOËL: Yeah, that sort of root node is typically the overarching task, the goal of what you want to do. And a common, I think, scenario for something like this would be, let's say, you're doing a Rails upgrade. And so, that root node is upgrade Rails. And a common thing that you might want to do is say, okay, let's go to the gem file, upgrade Rails, see what breaks, and then just keep fixing those things. That's working from the top down. And you're going to be in a long-running branch, and you're going to keep fixing things, fixing things, fixing things until you have found all the things but done all the things. And then you do a big bang upgrade that may have taken you weeks. As opposed to if you're working from the bottom up, you try to figure out, okay, what are all the subtasks? And that might take some exploration. You might not know upfront. But then you might say, okay, here, I can upgrade RSpec versus a dependency, or I need to change the interface of this class and ship all these pieces one at a time. And then, the final step is flipping that upgrade in the gem file, saying, okay, now I've upgraded Rails from 4 to 5, or whatever the version is that you're trying to do. STEPHANIE: I think you've really hit the nail on the head when it comes to trying to do something but not knowing what subtasks may compose of it and getting into that problem of, you know, having not broken it down, like, enough to really see all the dependencies. And, you know, maybe this is a conversation [chuckles] for another episode, but the skill of breaking up those tasks and exploring what those dependencies are, and being able to figure them out upfront before you start to just do that upgrade and then see what happens, that's definitely an area that I want to keep investing in. And I'm sure other people would be really curious about, too, to help them make their jobs easier. JOËL: I think one tip that I've learned that's really fun and that connects into all of this is sometimes you do end up with a cycle in your dependencies of tasks. A technique for breaking that up is a pattern that I have pitched multiple times on the show: the strangler fig pattern. And part of why it's so powerful is that it allows you to work incrementally by breaking up some of these cycles in your dependency graph. And one of the lessons that I've learned from that is that just because you have sort of an initial set of subtasks and you have a graph of them doesn't mean that you can't change them. If you're following strangler fig, what you're actually doing is introducing one or more new subtasks to that graph. But the way you introduce them breaks up that cycle. So, you can always add new tasks or split up existing ones as you get a better understanding of the work you need to do. It's not something that is fixed or set in stone upfront. STEPHANIE: Yeah, that's a really great tip. I think next time, what I really want to explore, you know, your heuristic of going from bottom up, yeah, sure, it sounds all fine and dandy. But how to get to a point where you're able to see everything at the bottom, right? And, like, when you are tasked, or you do start with the thing at the top, like, the end goal. Yeah, I'm sure that's something we'll explore [chuckles] another day. JOËL: On that note, shall we wrap up? STEPHANIE: Let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeee!!!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
Joël has been fighting a frustrating bug where he's integrating with a third-party database, and some queries just crash. Stephanie shares her own debugging story about a leaky stub that caused flaky tests. Additionally, they discuss the build vs. buy decision when integrating with third-party systems. They consider the time and cost implications of building their own integration versus using off-the-shelf components and conclude that the decision often depends on the specific needs and priorities of the project, including how quickly a solution is needed and whether the integration is core to the business's value proposition. Ruby class instance variables (https://www.codegram.com/blog/understanding-class-instance-variables-in-ruby/) Build vs Buy by Josh Clayton (https://thoughtbot.com/blog/build-vs-buy-considerations-for-new-products) Sustainable Rails (https://sustainable-rails.com/) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: My world has been kind of frustrating recently. I've been fighting a really frustrating bug where I'm integrating with a third-party database. And there are queries that just straight-up crash. Any query that instantiates an instance of an ActiveRecord object will just straight-up fail. And that's because before, we make the actual query, almost like a preflight query that fetches the schema of the database, particularly the list of tables that the database has, and there's something in this schema that the code doesn't like, and everything just crashes. Specifically, I'm using an ODBC connection. I forget exactly what the acronym stands for, Open Database connection, maybe? Which is a standard put up by Microsoft. The way I'm integrating it via Ruby is there's a gem that's a C extension. And somewhere deep in the C extension, this whole thing is crashing. So, I've had to sort of dust off some C a little bit to look through. And it's not super clear exactly why things are crashing. So, I've spent several days trying to figure out what's going on there. And it's been really cryptic. STEPHANIE: Yeah, that does sound frustrating. And it seems like maybe you are a little bit out of your depth in terms of your usual tools for figuring out a bug are not so helpful here. JOËL: Yeah, yeah. It's a lot harder to just go through and put in a print or a debug statement because now I have to recompile some C. And, you know, you can mess around with some things by passing different flags. But it is a lot more difficult than just doing, like, a bundle open and binding to RB in the code. My ultimate solution was asking for help. So, I got another thoughtboter to help me, and we paired on it. We got to a solution that worked. And then, right before I went to deploy this change, because this was breaking on the staging website, I refreshed the website just to make sure that everything was breaking before I pushed the fix to see that everything is working. This is a habit I've picked up from test-driven development. You always want to see your test break before you see it succeed. And this is a situation where this habit paid off because the website was just working. My changes were not deployed. It just started working again. Now it's gotten me just completely questioning whether my solution fixes anything. The difficulty is because I am integrating [inaudible 03:20] third-party database; it's non-deterministic. The schema on there is changing rather frequently. I think the reason things are crashing is because there's some kind of bad data or data that the ODBC adapter doesn't like in this third-party system. But it just got introduced one day; everything started breaking, and then somehow it got removed, and everything is working again without any input or code changes on my end. So, now I don't trust my fix. STEPHANIE: Oh no. Yeah, I would struggle with that because your reality has come crashing down, [laughs] or how you understood reality. That's tough. Where do you think you'll go from here? If it's no longer really an issue in this current state of the schema, is it worth pursuing further at this time? JOËL: So, that's interesting because it turns into a prioritization problem. And for this particular project, with the deadlines that we have, we've decided it's not worth it. I've opened up a PR with my fix, with some pretty in-depth documentation for why I thought that was the fix and what I think the underlying problem is. If this shows up again in the next few days, I'll have that PR that I can pull in and see if it fixes things, and if it doesn't, I'll probably just close that PR, but it'll be available for us if we ever run into this again. I've also looked at a few potential mitigating situations. Part of the problem is that this is a, like, massive system. The Rails app that I'm using really doesn't need to deal with this massive database. I think there's, you know, almost 1,000 tables, and I really only care about a subset of tables in, like, one underlying schema. And so, I think by reducing the permissions of my database user to only those tables that I care about, there's a lower chance of me triggering something like this. STEPHANIE: Interesting. What you mentioned about, you know, having that PR continue to exist will be really helpful for future folks who might come across the same problem, right? Because then they can see, like, all of the research and investigation you've already done. And you may have already done this, but if you do think it's a schema issue, I'm curious about whether the snapshot of the schema could be captured from when it was failing to when it has magically gotten fixed. And I wonder if there may be some clues there for some future investigator. JOËL: Yeah. I'm not sure what our backup situation is because this is a third-party system, so I'd have to figure out what things are like in the admin interface there. But yeah, if there is some kind of auditing, or snapshots, or backups, or something there, and I have rough, you know, if I know it's within a 24-hour period, maybe there's something there that would tell me what's happening. My best guess is that there's some string that is longer than expected or maybe being marked as a CHAR when it should be a VARCHAR, or maybe something that's not a non-UTF-8 encoded character, or something weird like that. So, I never know exactly what was wrong in the schema. There's some weird string thing happening that's causing the Ruby adapter to blow up. STEPHANIE: That also feels so unsatisfying [laughs] for you. I could imagine. JOËL: Yeah, there's no, like, clean resolution, right? It's a, well, the bug is gone for now. We're trying to make it less likely for it to pop up again in the future. I'm trying to leave some documentation for the next person who's going to come along, and I'm moving forward, fingers crossed. Is that something you've ever had to do on one of your projects? STEPHANIE: Given up? Yes. [laughter] I think I have definitely had to learn how to timebox debugging and have some action items for when I just can't figure it out. And, you know, like we mentioned, leaving some documentation for the next person to pick up, adding some additional logging so that maybe we can get more clues next time. But, you know, realizing that I do have to move on and that's the best that I can do is really challenging. JOËL: So, you used two words here to describe the situation: one was giving up, and the other one was timebox. I think I really like the idea of describing this as timeboxing. Giving up feels kind of like, defeatist. You know, there's so many things that we can do with our time, and we really have to be strategic with how we prioritize. So, I like the idea of describing this as a timeboxing situation. STEPHANIE: Yeah, I agree. Maybe I should celebrate every time that I successfully timebox something [laughs] according to how I planned to. [laughs] JOËL: There's always room to extend the timebox, right? STEPHANIE: [laughs] It's funny you bring up a debugging mystery because I have one of my own to share today. And I do have to say that it ended up being resolved, [chuckles] so it was a win in my book. But I will call this the case of the leaky stub. JOËL: That sounds slightly scary. STEPHANIE: It really was. The premise of what we were trying to figure out here was that we were having some flaky tests that were failing with a runtime error, so that was already kind of interesting. But it was quickly determined it was flaky because of the tests running in a certain order, so-- JOËL: Classic. STEPHANIE: Right. So, I knew something was happening, and any tests that came after it were running into this error. And I was taking a look, and I figured out how to recreate it. And we even isolated to the test itself that was running before everything else, that would then cause some problems. And so, looking into this test, I saw that it was stubbing the find method on an ActiveRecord model. JOËL: Interesting. STEPHANIE: Yeah. And the stubbed value that we were choosing to return ended up being referenced in the tests that followed. So, that was really strange to me because it went against everything I understood about how RSpec cleans up stubs between tests, right? JOËL: Yeah, that is really strange. STEPHANIE: Yeah, and I knew that it was referencing the stub value because we had set a really custom, like, ID value to it. So, when I was seeing this exact ID value showing up in a test that seemed totally unrelated, that was kind of a clue that there was some leakage happening. JOËL: So, what did you do next? STEPHANIE: The next discovery was that the error was actually raised in the factory setup for the failing tests and not even getting to running the examples at all. So, that was really strange. And digging into the factories was also its own adventure because there was a lot of complexity in the factories. A lot of them used hooks as well that then called some application code. And it was a wild goose chase. But ultimately, I realized that in the factory setup, we were calling some application code for that model where we had stubbed the find, and it had used the find method to memoize a class instance variable. JOËL: Oh no. I can see where this is going. STEPHANIE: Yeah. So, at some point, our model.find() returned our, you know, stub value that we had wanted in the previous test. And it got cached and just continued to leak into everything else that eventually would try to call that memoized method when it really should have tried to do that look-up for a separate record. JOËL: And class instance variables will persist between tests as long as they're on the same thread, right? STEPHANIE: Yeah, as far as I understand it. JOËL: That sounds like a really frustrating journey. And then that moment when you see the class instance variable, and you're like, oh no, I can't believe this is happening. STEPHANIE: Right? It was a real recipe for disaster, I think, where we had some, you know, really complicated factories. We had some sneaky caching issues, and this, you know, totally seemingly random runtime error that was being raised. And it was a real wild goose chase because there was not a lot of directness in going down the debugging path. I feel like I went around all over the codebase to get to the root of it. And, in the end, you know, we were trying to come up with some takeaways. And what was unfortunate was that you know, like, normally, stubbing find can be okay if you are, you know, really wanting to make sure that you are returning your mocked value that you may have, like, stubbed some other stuff on in your test. But because of all this, we were like, well, should we just not stub find on this really particular model? And that didn't seem particularly sustainable to make as a takeaway for other developers who want to avoid this problem. So, in the end, I think we scoped the stub to be a little more specific with the arguments that we wanted to target. And that was the way that we went forward with the particular flaky test at hand. JOËL: It sounds like the root cause of the problem was not so much the stub as it was the fact that this value is getting cached at the class level. Is that right? STEPHANIE: Yes and no. It seems like a real pain for running the tests. But I'm assuming that it was done for a good reason in production, maybe, maybe not. To be fair, I think we didn't need to cache it at all because it's calling a find, which is, you know, should be pretty quick and doesn't need to be cached. But who knows? It's hard to tell. It was really old code. And I think we were feeling also a little nervous to adjust something that we weren't sure what the impact would be. JOËL: I'm always really skeptical of caching. Caching has its place. But I think a lot of developers are a little too happy to introduce one, especially doing it preemptively that, oh well, we might need a cache here, so why not? Let's add that. Or even sometimes, just as a blind solution to any kind of slowness, oh, the site is slow; let's throw a cache here and hope for the best. And the, like, bedrock, like, rule zero of any kind of performance tuning is you've got to measure before and after and make sure that the change that you introduce actually makes things better. And then, also, is it better enough speed-wise that you're willing to pay any kind of costs associated to maintaining the code now that it's more complex? And a lot of caches can have some higher carrying costs. STEPHANIE: Yeah, that's a great point. This debugging mystery an example of one of them. JOËL: How long did it take you to figure out the solution here? STEPHANIE: So, like you, I actually was on a bit of the incorrect path for a little while. And it was only because this issue affected a different flaky test that someone else was investigating that they were able to connect the dots and be like, I think these, you know, two issues are related. And they were the ones who ultimately were able to point us out to the offending test if you will. So, you know, it took me a few days. And I imagine it took the other developer a few days. So, our combined effort was, like, over a week. JOËL: Yep. So, for all our listeners out there, you just heard that Stephanie and I [laughs] both went on multi-day debugging journeys. That happens to everyone. Just because we've been doing this job for years doesn't mean that every bug is, like, a thing that we figure out immediately. So, separately from this bug that I've been working on, a big issue that's been front of mind for me on this project has been the classic build versus buy decision. Because we're integrating with a third-party system, we have to look at either building our own integration or trying to use some off-the-shelf components. And there's a few different levels of this. There are some parts where you can actually, like, literally buy an integration and think through some of the decisions there. And then there's some situations where maybe there's an open-source component that we can use. And there's always trade-offs with both the commercial and the open-source situation. And we have to decide, are we willing to use this, or do we want to build our own? And those have been some really interesting discussions to have. STEPHANIE: Yeah. I think you actually expanded this decision-making problem into a build versus buy versus open source because they are kind of, you know, really different solutions with different outcomes in terms of, you know, maintenance and dependencies, right? And that all have, like, a little bit of a different way to engage with them. JOËL: Interesting. I think I tend to think of the buy category, including both like commercial off-the-shelf software and also open-source off-the-shelf software, things that we wouldn't build custom for ourselves but that are third-party components that we can pull in. STEPHANIE: Yeah, that's interesting because I had a bit of a different mental model because, in my head, when you're buying a commercial solution, you, you know, are maybe losing out on some opportunities for customization or even, like, forking it on your own. So, with an open-source solution, there could be an aspect of making it work for you. Whereas for a commercial solution, you really become dependent on that other company and whether they are willing to cater [laughs] to your needs or not. JOËL: That's fair. For something that's closed-source where you don't actually have access to the code, say it's more of a software as a service situation, then, yeah, you're kind of locked in and hoping that they can provide the needs that you have. On the flip side, you are generally paying for some level of support. The quality of that varies sometimes from one vendor to another. But if something goes wrong, usually, there's someone you can email, someone you can call, and they will tell you how to fix the problem, or they will fix it on their end. STEPHANIE: For the purposes of this conversation, should we talk about the differences, you know, building yourself or leaning on an existing built-out solution for you? JOËL: The project I'm working on is integrating with a Snowflake data warehouse, which is an external place that stores data accessible through something SQL-like. And one of the things that's attractive about this is that you can pull in data from a variety of different sources, transform it, and have it all stored in a kind of standardized structure that you can then integrate with. So, for pulling data in, you can build your own sort of ingestion pipeline, if you want, with code, and their APIs, and things. But there are also third-party vendors that will give you kind of off-the-shelf components that you can use for a lot of popular other data sources that you might want to pull. So, you're saying; I want to pull from this external service. They've probably got a pre-built connector for it. They can also do things like pull from an arbitrary Postgres database on some other server if that's something you have access to. It becomes really attractive because all you need to do is create an account on this website, plug in a few, like, API keys and URLs. And, all of a sudden, data is just flowing from one third-party system into your Snowflake data Warehouse, and it all just kind of works. And you don't have to bother with APIs, or ODBC, or any of that kind of stuff. STEPHANIE: Got it. Yeah, that does sound convenient. As you were talking about this, I was thinking about how if I were in the position of trying to decide how to make that integration happen, the idea of building it would seem kind of scary, especially if it's something that I don't have a lot of expertise in. JOËL: Yeah, so this was really interesting. In the beginning of the project, I looked into a little bit of what goes into building these, and it's fairly simple in terms of the architecture. You just need something that writes data files to typically something like an S3 bucket. And then you can point Snowflake to periodically pull from that bucket, and you write an import script to, you know, parse the columns and write them to the right tables in the structure that you want inside Snowflake. Where things get tricky is the actual integration on the other end. So, you have some sort of third-party service. And now, how do you sort of, on a timer maybe, pull data from that? And if there are data changes that you're synchronizing, is it just all append-only data? Or are you allowing the third-party service to say, "Hey, I deleted this record, and you should reflect that in Snowflake?" Or maybe dealing with an update. So, all of these things you have to think about, as well as synchronization. What you end up having to do is you probably boot up some kind of small service and, you know, maybe this is a small Ruby app that you have on Heroku, maybe this is, like, an AWS Lambda kind of thing. And you probably end up running this every so many seconds or so many minutes, do some work, potentially write some files to S3. And there's a lot of edge cases you have to think about to do it properly. And so, not having to think about all of those edge cases becomes really enticing when you're looking to potentially pay a third party to do this for you. STEPHANIE: Yeah, when you used the words new service, I bristled a little bit [laughs] because I've definitely seen this happen maybe on a bit of a bigger scale for a tool or solution for some need, right? Where some team is formed, or maybe we kind of add some more responsibilities to an existing team to spin up a new service with a new repo with its own pipeline, and it becomes yet another thing to maintain. And I have definitely seen issues with the longevity of that kind of approach. JOËL: The idea of maintaining a fleet of little services for each of our integrations seemed very unappealing to me, especially given that setting something like this up using the commercial approach probably takes 30 minutes per third-party service. There's no way I'm standing up an app and doing this whole querying every so many minutes, and getting data, and transforming it, and writing it to S3, and addressing all the edge cases in 30 minutes. And it's building something that's robust. And, you know, maybe if I want to go, like, really low tech, there's something fun I could do with, like, a Zapier hook and just, like, duct tape a few services together and make this, like, a no-code solution. I still don't know that it would have the robustness of the vendor. And I don't think that I could do it in the same amount of time. STEPHANIE: Yeah. I like the keyword robustness here because, at first, you were saying, like, you know, this looked relatively small in scope, right? The code that you had to write. But introducing all of the variables of things that could go wrong [laughs] beyond the custom part that you actually care about seemed quite cumbersome. JOËL: I think there's also, at this point, a lot of really interesting prioritization questions. There are money questions, but there are also time questions you have to think about. So, how much dev time do we want to devote upfront to building out these integrations? And if you're trying to move fast and get a proof of concept out, or even get, like, an MVP out in front of customers, it might be worth paying more money upfront to a third-party vendor because it allows you to ship something this week rather than next month. STEPHANIE: Yeah. The "How soon do you need it?" is a very good question to ask. Another one that I have learned to include in my arsenal of, you know, evaluating this kind of stuff comes from a thoughtbot blog by Josh Clayton, where he, you know, talks about the build versus buy problem. And his takeaway is that you should buy when your business is not dependent on it. JOËL: When it's not part of, like, the core, like, value-add that your business is doing. Why spend developer time on something that's not, like, the core thing that your product is when you can pay someone else to do it for you? And like we said earlier, a lot of that time ends up being sunk into edge cases and robustness and things like that to the point where now you have to build an expertise in a, like, secondary thing that your business doesn't really care about. STEPHANIE: Yeah, absolutely. I think this is also perhaps where very clear business goals or a vision would come in handy as well. Because if you're considering building something that doesn't quite support that vision, then it will likely end up continuing to be deprioritized over the long term until it becomes this thing that no one is accountable for maintaining and caring for. And just causes a lot of, honestly, morale issues is what I've seen when some service that was spun up to try to solve a particular problem is kind of on its last legs and has been really neglected, and no one wants to work on it. But it ends up causing issues for the rest of the development team. But then they're also really focused on initiatives that actually do provide the business value. That is a really hard balancing act that I've seen teams struggle with. JOËL: Earlier this year, we were talking about the book Sustainable Rails. And it really hammers home the idea of a carrying cost for the code, and I think that's exactly what we're talking about here. And that carrying cost can be time and money. But I like that you also mentioned the morale effects. You know, that's a carrying cost that just sort of depresses the productivity of your team when morale is low. STEPHANIE: Yeah, absolutely. I'm curious if we could discuss some of the carrying costs of buying a solution and where you've seen that become tricky. JOËL: The first thing to look at is the literal cost, the money aspect of things. And I think it's a really interesting situation for the business models for these types of Snowflake connectors because they typically charge by the amount of data that you're transmitting, so per row of data that you're transmitting. And so, that cost will fluctuate depending on whether the third-party service you're integrating with is, like, really chatty or not. When you contrast that to building, building typically has a relatively fixed cost. It's a big upfront cost, and then there's some maintenance cost to go with it. So, if I'm building some kind of integration for, let's say, Shopify, then there's the cost I need to build up front to integrate that. And if that takes me, I don't know, a week or two weeks, or however long it is, you know, that's a pretty big chunk of time. And my time is money. And so, you can actually do the math and say, "Well, if we know that we're getting so many rows per day at this rate from the commercial vendor, how many weeks do we have to pay for the commercial one before we break even and it becomes more expensive than building it upfront, just in terms of my time?" And sometimes you do that math, and you're like, wow, you know, we could be going on this commercial thing for, like, two years before we break even. In that case, from a purely financial point of view, it's probably worth paying for that connector. And so, now it becomes really interesting. You say, okay, well, which are the connectors that we have that are low volume, and which are the ones that are high volume? Because each of them is going to have a different break-even point. The ones that you break even after, you know, three or four weeks might be the ones that become more interesting to have a conversation about building. Whereas some of the others, it's clearly not worth our time to build it ourselves. STEPHANIE: The way you described this problem was really interesting to me because it almost sounds like you found the solution somewhere in the middle, potentially, where, you know, you may try building the ones that are highest priority, and you end up learning a lot from that experience, right? That could make it easier or at least, like, set you up to consider doing that moving forward in the future if you find, like, that is what is valuable. But it's interesting to me that you kind of have the best of both worlds of, like, getting the commercial solutions now for the things that are lower value and then doing what you can to get the most out of building a solution. JOËL: Yeah. So, my final recommendation ended up being, let's go all commercial for now. And then, once we've built out something, and because speed is also an issue here, once we've built out something and it's out with customers, and we're starting to see value from this, then we can start looking at how much are we paying per week for each of these connectors? And is it worth maybe going back and building our own for some of these higher-volume connectors? But starting with the commercial one for everything. STEPHANIE: Yeah, I actually think that's generally a pretty good path forward because then you are also learning about how you use the commercial solution and, you know, which features of it are critical so that if you do eventually find yourselves, like, maybe considering a shift to building in-house, like, you could start with a more clear MVP, right? Because you know how your team is using an existing product and can focus on the parts that your business are dependent on. JOËL: Yeah, it's that classic iterative development style. I think here it's also kind of inspired by a strategy I typically use for performance, which is make it work before you try to make it fast. And, actually, make it work, then profile, then measure, find the hotspots, and then focus on making those things fast. So, in this case, instead of speed, we're talking about money. So, it's make it work, then profile, find the parts that are expensive, and make the trade-off of, like, okay, is it worth investing into making that part less expensive in terms of resources? STEPHANIE: I like that as a framework a lot. JOËL: A lot of what we do as programmers is optimization, right? And sometimes, we're optimizing for execution time. Sometimes we're optimizing for memory cost, and sometimes we're optimizing for dollars. STEPHANIE: Yeah, that's really interesting because, with the buy solution, you know very clearly, like, how much the thing will cost. Whereas I've definitely seen teams go down the building route, and it always takes longer than expected [laughs], and that is money, right? In terms of the developer's time, for sure. JOËL: Yeah, definitely, like, add some kind of multiplier when you're budgeting out that build alternative because, quite likely, there are some edge cases that you haven't thought about that the commercial partner has, and you will have to spend more time on that than you expected. STEPHANIE: Yeah, in addition to whatever opportunity cost of not working on something that is driving revenue for the business right now. JOËL: Exactly. STEPHANIE: So, the direction of this conversation ended up going kind of towards, like, what is best for the team at, like, a product and company level. But I think that we make these decisions a lot more frequently, even when it comes to whether we pull in a gem or, you know, use an open-source tool or not. And I would be really interested in discussing more of that in another episode. JOËL: Yeah. That gets into some controversial takes, right? It's the evergreen topic of: do we build it ourselves, or do we pull in some kind of third-party package? STEPHANIE: Something for the future to look forward to. On that note, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeeee!!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
Stephanie had a small consulting win: saying no to a client. GeoGuessr is all the rage for thoughtbot's remote working culture, which leads to today's topic of forming human connections in a virtual (work) environment. GeoGuessr (https://www.geoguessr.com/) Strategies for saying no by Elle Meredith (https://www.youtube.com/watch?v=_2zWwwjnuUA) NYT Let's Ignore Each Other in the Same Room (https://www.nytimes.com/2021/09/24/well/live/parallel-play-for-adults.html) Random question generator (https://standup-questions.vercel.app/) Transcript: JOËL: And this is just where it ends. [laughter] Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. STEPHANIE: And I'm Stephanie Minn. And together, we're here to share a bit of what we've learned along the way. JOËL: So, Stephanie, what's new in your world? STEPHANIE: So, I have a small consulting win, or even just a small, like, win as a human being [laughs] that I want to share, which is that I feel good about a way that I handled saying no to a stakeholder recently. And, you know, I really got to take them where I can get it because that is so challenging for me. But I feel really glad because we ended up kind of coming out the other side of it having a better understanding of each other's goals and needs. And so, basically, what happened was I was working on a task, and our product owner on our team asked me if it could be done by next week. And immediately, I wanted to say, "Absolutely not." [laughs] But, you know, I took a second and, you know, I had the wherewithal to ask why. You know, I was kind of curious, like, where was this deadline coming from? Like, what was on her radar that, like, wasn't on mine? And she had shared that, oh, you know, if we were able to get it out before this big launch, she was thinking that it actually might make our customer support team's lives easier because we were kind of taking away access to something before some new features rolled out. And, you know, there might be some customers who would complain. And with that information, you know, that was really helpful in helping me understand. And I'm like, yeah, like, that seems like a helpful thing to know, so I could try to strive for it. Because I also, like, want to make that process go easier as well. But I told her that I'd let her know because I honestly wasn't sure if it was possible to do by next week. And after a little bit of, you know, more digging, kind of seeing how my progress was going, in the end, I had to say that I didn't feel confident that we could finish it in time for that deadline because of the other risks, right? Like, I didn't want to just release this thing without feeling good about the plan that we had. And so, that was my small, little win in saying no, and I feel very proud of myself for it. JOËL: I'm proud of you too. That's not easy to just do in the first place, and then to do it well is a whole other level. It sounds, though, that you came out of the other side with the client with almost, like, a better relationship. STEPHANIE: Yeah, I think so. In general, you know, I really struggle when people do end up getting into that debate of, like, "Well, I need this." And someone else says, "Well, I need this other thing." And, you know, at some point, it kind of gets a bit unproductive, right? But I think this was a very helpful way for me to see a path forward when maybe we, like, have different priorities. But, like, can we better understand each other and the impact of them to ultimately, like, make the best decision? The other thing that I wanted to share that I learned recently was there was a recent RailsConf talk by Elle Meredith, and it was about strategies to say no, and I watched it. And one really cool thing that I learned was that the word priority, you know, when it was first created, it actually didn't really have, like, a plural form. There was really only ever, like, a singular priority. And it wasn't until, I think, you know, the recent century or something like that, that people started to use it in a plural form. And that was really enlightening to me. I think it made me rethink the word and how I use it, and it made a lot of sense, too. Because at any given moment, you know, really, you can't be doing more than one thing; I mean, you can try. I know that I have been guilty of multitasking. But that, you know, doesn't always serve me. I never end up doing all of the things that I'm trying to do well. And I would be really curious to kind of, you know, when I do feel that urge, like, think a little bit about, like, what is the one thing that I should be doing right now that is the highest priority? JOËL: I would definitely second that recommendation for this talk. I actually got to see it live at RailsConf, and it was excellent. STEPHANIE: So, Joël, what's new in your world? JOËL: I got to participate in a really fun event at thoughtbot today. We got together with some other people on the Boost Team and played a few rounds of GeoGuessr. And for those who are not familiar with this game, it drops you randomly somewhere in the world in Google Street View. You can move around. And there's a timer, and you have to drop a pin on a map where you think you are. So, you're walking through the streets, and you're like, okay, well, I don't know this language. I'm not sure where we're going. You know, with the vibes going here, I'll bet, you know, this looks like maybe southern China, and then you drop a pin. And oh no, turns out it was actually Singapore. And there's all these little hints and things. People who are really into it have learned all these tricks, and they can be really good. Sara Jackson, who is our resident GeoGuessr expert, is excellent at this. But it was a good time. STEPHANIE: Yeah, it was really fun. I liked that we played a cooperative mode where we were all kind of helping each other out. And so, maybe someone is, like, exploring on the map and sees a street sign and is like, "Oh, like, that looks like this language." And someone else is like, "Oh yeah, like, that is that." Or like, "No, I think it's actually this other language," and sharing all of the different, like, pieces of information that we're finding to get closer and closer to what it might be. And then we celebrate whoever ends up getting the closest because, at some point, it's kind of just, like, just a luck of the pin, right? Where maybe you happen to click on, like, the right place. But it's always really exciting when we're like, wow, like, Sara was only 500 kilometers away in finding the exact place that we were served. So, I had a good time as well. JOËL: So, speaking of cooperative events, this was a work event that we did. We just got together and played a game. And, for me, that was a really fun way to connect with some of my colleagues. I'm curious, what are your thoughts on things that you've seen done well in companies that are remote-first that really foster a sense of connection and community among a team? STEPHANIE: I think this worked especially well today because it was kind of scheduled in regular time that we have as a team to me. And sometimes, you know, the meeting topics are a bit more work-focused. But what I really like is that anyone on the team can host one of these meetings. We have them biweekly, and we just call them Boost biweeklies. Boost is the team that Joël and I are on. JOËL: Naming is the hardest problem in computer science. STEPHANIE: It really is. But I really like that people can bring, you know, a little bit of their own flavor to this meeting. So, whoever is host just kind of comes up with something to do. And sometimes it's like show and tell. You know, other times it is more of like, you know, what's the update on some of the projects that we're doing? Other times, it's the Spicy Takes Lightning Talks that we've kind of mentioned on the podcast before. And yeah, it is just a really nice, like, time for us to get together. And I also feel like I learn something about my co-workers every time that we meet, whether it's the person who is hosting the meeting and kind of where their interests are. I think someone even did, like, chair yoga once and guided the team in doing that. Or because they are more casual, right? Sometimes we just play a game, and I really enjoy that nice break in my day. JOËL: Do you find that the particular style of these meetings makes you feel more connected to your colleagues? Would you prefer just kind of game day one, like we had today, versus maybe, like, lightning talks or a presentation on security or something like that? STEPHANIE: I actually think the diversity is what makes it special. I get to see, you know, a bunch of different sides of my co-workers and, you know, some days, the topic is a little more serious, and that can be really connecting. Another Boost Team member had hosted a biweekly where we kind of shared the challenges of, like, consulting work and, like, onboarding onto a new project and sharing what might be difficult and, like, how we might be feeling when we do join a new project. And I think that was really helpful because it was very validating for something that I thought, like, maybe I felt a little bit more alone in. And the tone was a little bit more, like, earnest and serious. But I came away with it feeling very supported by my team, right? And other times, it is just silliness and fun [laughs], which, you know, is also important. Like, we need to have fun every once in a while. JOËL: That's awesome. Do you feel like when you go to these meetings, you're looking more for knowledge or looking more for connection? STEPHANIE: I think both because knowledge sharing is also, you know, can be really helpful. Like, I have enjoyed learning that, you know, so and so is, like, a GeoGuessr expert, Sara, right? And so, if I ever, like, find myself needing [chuckles] someone to go to about my Google Street View or world geography questions, I know that I can go to her. And, like, knowing that about her, like, makes me feel more connected to her. So, I think both are true. So, we have been talking about a meeting style form of connecting in a remote workplace, but I'm really curious about your thoughts on asynchronous versus synchronous communication and how you find connection with a format that is more asynchronous, not just, you know, being in a meeting together. JOËL: That's really challenging. I think I personally find that something that's mostly synchronous with maybe a little bit of a lag works pretty well for me, so something like Slack, where it's not exactly real-time because someone could take some time to come back to me. But for working hours overlap, there's likely some close-to-synchronous conversation happening. But, you know, I can still get up and, you know, refill my cup of coffee, or it's not quite like I'm sitting in front of a camera. So, I think that, for many things, hits the sweet spot for myself. But there's definitely some things where I think you want a higher, like, information density. And that's, I think, where the synchronous face-to-face meeting really shines. STEPHANIE: Information density. I haven't heard that phrase before, but I like it. JOËL: The idea being, you know, how much information or how many words are you sharing back and forth, you know, per minute or something like that. And when you're talking on a call, you can do a lot more of that than you can going back and forth over Slack or writing an email. STEPHANIE: So, I would say that at thoughtbot, we have a pretty asynchronous Slack culture, which I think can be quite different from other, you know, places I've worked at before or other Slack spaces that I've seen. And I actually find it a little bit harder to engage in that way. We have a dev channel where, you know, people chat about different technical topics. And sometimes, you know, those threads go, like, 40 replies long. And I think you tend to engage a lot more in those. And I'm curious, like, does that scratch the itch for you in terms of that perfect, like, async, kind of some amount of lag for you to be doing other things, kind of doing your work, but then being able to come back and pick up the conversation where I left off? JOËL: Yes, that is really nice because, you know, maybe I have a meeting or something, and I'm not there when the conversation starts, but I don't miss out. And I get to join in, you know, maybe 30 minutes after everyone else. You know, sometimes you don't want to just, like, restart a conversation that's happened and is done. But some of these things will kind of be going on and off all day. And those can be really fun, especially sometimes, like, a new person joins the thread and brings in a totally new perspective or a new angle that kind of, like, breathes new life into it and kind of gives everyone a new perspective. STEPHANIE: Nice. I also think there's something to the idea of seeing more people engage with something that then invites other people to engage with it. JOËL: I would agree with that. It's definitely exciting to see a thread, and it's not like, oh, it's empty, and I'm the only one who's put a response in here. When there is a lot of back and forth, you can almost feel the excitement. And that gets me hyped to, like, keep it going. STEPHANIE: At a previous workplace in our Slack, we had a, like, virtual Jeopardy channel. JOËL: Ooh. STEPHANIE: And so, there was a little Jeopardy bot. And I guess whenever someone, you know, had a low on what they were doing, they would just start, you know, tagging the bot to pose a question. And anyone can answer, right? But once you kind of got the ball rolling, you would see other people start playing as well. And it would get really active for segments of 30 minutes or so. And I always really enjoyed that because, yeah, it was a way for me to remember like, oh yeah, there's, like, other people also, like, typing away on their little keyboards, and we're all here together. But it was really interesting to see, like, when someone got it rolling, like, oh, other people, like, joined in. JOËL: Yeah, being able to see small things like that can really build a sense of connection, even if you're not yourself directly participating. STEPHANIE: Yeah. I think another thing I've been trying out lately is letting people know that I'm in a meeting space and offering to virtually co-work. So, you know, during the early days of when thoughtbot went remote, we had a lounge virtual meeting space for people to hang out with and, you know, get that face time that they weren't getting anymore since we weren't in the office. And, you know, I think that has kind of decreased in terms of engagement over, you know, several years now. And obviously, people have a lot of meeting fatigue and stuff like that. But I was kind of in a mood to revive it a little bit because, yeah, I kind of got over the meeting fatigue and was wanting more face time with people. And the unfortunate thing, though, is that, like, no one was showing up to this room anymore. So, you know, even if someone wanted to hang out in it, you know, they go in. They see no one's there, you know, maybe they stay for a few minutes, but then they're like, okay, well, I'm just going to leave now. And a couple of thoughtboters and I have been trying to revive it where we'll post in our general channel, like, "Hey, like, I'm in this meeting room. Like, come hang out for the next hour if you would like." And that's been working well for me. I have had a few, like, really nice lounge, virtual co-working hangout sessions. Even if one person shows up, honestly, like, that fulfills my want to just, like, speak to another human. [laughs] JOËL: What does virtual co-working look like? Are you just kind of each doing work, but you've got a video camera on, and you're just aware of the presence of someone else? Do you kind of have, like, random breaks where you talk? What is that experience like? STEPHANIE: Oh yeah, that's a good question. I have to say; for me, I'm just talking to the other [laughs] person at that point. I'm not really doing a whole lot of work. And, you know, in some ways, I almost think that, like, in those moments, I am really wanting to chat with someone and, like, that's okay, right? JOËL: It's like a virtual water cooler for you. STEPHANIE: Yeah, exactly. Like, that would be the moment if I were working in office that I would wander into the kitchen looking for a snack but also an unsuspecting victim to start [laughs] a conversation with. JOËL: I feel you. I feel you. I have absolutely done that. STEPHANIE: Yeah. And that's actually what makes me feel a little less guilty about it. Because, you know, when I was working in the office, like, that was such a big part of my day, and it's kind of what kept me motivated. And at home, I do find myself, like, a lot more productive. In fact, like, I think I am because I'm, you know, not spending that time wandering into the kitchen. But at what cost? [laughs] At the cost of, like, me feeling very, like, lonely and, like, kind of burnt out at the end of the day. So, injecting my day with some of these moments, I think, is important to me. And also, again, like, I know that I'm being really productive in my, like, heads-down-time that I want to, you know, allow myself to just like, get that dose of connection. JOËL: I know, for me, when we were doing things like this in person as well, those conversations that happen, yes, there's some random, frivolous stuff, but sometimes, it is a conversation related to work that I'm doing. Because, you know, someone who's not on my project is like, "Hey, how's your project going?" Or whatever. I'm like, "Oh, well, I'm, you know, doing this ODBC connection, and I'm kind of stuck." And, you know, we kind of talk about a few things. It's like, "Oh, did you know about this gem?" And it's like, "Wait, why didn't I talk to you earlier? Because this totally solves my problem." STEPHANIE: Yeah, I think that being a sounding board is so valuable as well. So, I guess I enjoy virtual co-working, not necessarily, you know, us, like, sitting together and doing our work separately. Though I know that there's value in that, especially in real life. Like, I remember reading an article. I'll try to find it and link it. But the idea of just, like, sharing space with someone can be, like, a form of bonding. But I do really enjoy just hearing about what other people are working on and just kind of, like, asking questions about it, right? And maybe we do take away, like, a new perspective or, like, have some insights about, like, the work itself. And, yeah, we don't really get that when we're working remotely by ourselves because there's no one to turn to and be like, "Hey, what do you think about this problem?" JOËL: I love how no matter what the topic is that we're discussing on this show, you always have a book or an article or something that you've read that you can reference. And I think that's amazing. STEPHANIE: Thank you. JOËL: So, you're talking about things that have really helped you feel a deeper sense of connection. I had a realization recently about the power of physical items. In particular, as consultants, sometimes we work with clients who, for security reasons, want us to work on a dedicated laptop for this particular client. And so, we'll have clients maybe—well, now that we're remote—ship us a laptop, and we work on that laptop when we're doing client stuff, and then on our thoughtbot laptops when we're doing thoughtbot things. And when I've been on clients like that, I have felt much more isolated from the thoughtbot team. And just, like, physically switching over to the thoughtbot laptop, all of a sudden, gives me that feeling of connection. And there's something I can't quite explain about the power of the physical item. And, say, I'm working on the thoughtbot laptop today with, you know, thoughtbot Slack in the background or whatever, and I feel more connected to my colleagues. STEPHANIE: Yeah, that is really curious. Did you also have thoughtbot communication channels open in your client laptop during that time? JOËL: I did, and yet still felt more separation. STEPHANIE: Yeah, that's really interesting. The way you're describing it, it was almost like, you know, the main laptop that you work with, with your, like, all of the settings that you like, all of your little shortcuts, you know, the autocomplete to the whatever, like, channels of communication that you are used to seeing. In some ways, that almost feels like home a little bit. And I wonder if working on a client laptop almost kind of feels like, you know, being in a stranger's house, right? JOËL: There's definitely an element of that. Yeah, all the little things I've fine-tuned, some of the productivity software I have on there that are just, you know, I can one by one set them up on the client laptop, depending on permissions. But yeah, it's never quite the same. STEPHANIE: So, when you are in a situation where you're mostly working from a client laptop and maybe embedded in their Slack workspace, embedded in their team, how do you go about investing in connection with your client team? JOËL: So, you know what's kind of weird? Is that when I'm on a client laptop, I feel less connected to my colleagues at thoughtbot, but the reverse is not necessarily true. I don't feel more connected to colleagues on a client team on a client laptop than I would on my thoughtbot laptop. So, I'm not exactly sure what the psychology is going on there. But I feel kind of most connected to both when I'm working on my thoughtbot laptop, which is perhaps a bit strange. STEPHANIE: Oh, yeah, that is interesting. I think, in general, there's an aspect of joining a new client team and trying to figure out the culture there and how you might engage with it, right? And how what you bring to the table kind of fits in with how they do things, and how they talk about things, and how they behave. In some ways, it's kind of, like, you know, an outsider joining this, like, in-group, right? So, I've definitely realized that the ways that I engage and feel connected at thoughtbot, like, may or may not work for the client team that I'm joining. JOËL: Yeah. And onboarding onto a client team is not just a technical exercise, right? It's also a social process where you want to get to know the other people on your team, get to sort of integrate into the way they work, their processes, hopefully, build a little bit of, like, personal connection with individuals because all of those are going to help me do my job better tomorrow, and the day after, and the week after that. STEPHANIE: Yeah. I had mentioned previously that one thing that I've been enjoying on my client team is our daily sync question. So, a random question will be generated, you know, like, "What are you eating for dinner today?" Or, like, "What are you looking forward to this weekend?" And folks are able to share. And the fun thing is that sometimes the answer to the question is longer than their work update itself. JOËL: Nice. STEPHANIE: But that is actually the, you know, the beauty of it because we all just, like, get to laugh and get to, you know, chime in. And I'm like, "Oh yeah, like, that sounds delicious, like, what you're eating for dinner tonight." But, like, that would not work for our Boost Team's sync because, you know, it's a much bigger meeting with sometimes up to, you know, 20 to almost 30 people and, like, we can't quite have as much time spent talking about the fun question of the day. So, I definitely think that, you know, it depends your team size, and makeup, and whatnot. JOËL: Are those questions kind of preset, or do you all get to contribute questions to the list? STEPHANIE: We brainstormed the questions one retro when we were realizing that we were kind of getting a little bored of the existing question that we had. And we came up with a handful that is plugged into, like, a website, or, like, an app that randomly, you know, picks the question of the day. And so, I think, again, when we get a little bored of the ones that we have in rotation, we'll throw in some curveballs in there. JOËL: Have you ever considered adding "What's new in your world?" to this rotation? STEPHANIE: It's funny you mentioned that because it's actually the question that we got a little bit stale on. [laughs] JOËL: Really? STEPHANIE: And we needed to inject some new life into, yeah. It's a classic, you know. But I think the variety is nice, especially since we're meeting almost every day. And before we started recording, you and I were just talking about how even sometimes it's tough to think of something that's new in our world [laughs] because we don't always live the most interesting and, you know, new lives. And sometimes, we kind of just have to dig deep to come up with something, and we only meet weekly. [laughs] JOËL: I can definitely see how doing this daily might be more challenging. I think there's also value in questions that are a little bit more focused. Part of what's fun for this podcast is that "What's new in your world?" is so kind of broad. But maybe for something daily, having something really specific, like, what did you eat for dinner tonight? Means that you aren't just kind of drawing blanks in your mind, like, uh, uh, what is new in my world? What have I done? I don't know; I have a boring life. I don't do anything. Kind of panic mode that you can sometimes get when you hit a meeting. And so, I do know that when I've been sometimes in situations with people where you have questions like that, I've tended to really appreciate the more targeted ones. STEPHANIE: Yeah, that's so interesting you mentioned that because I think in social situations, there's usually maybe, like, someone who is really good at asking those, like, specific questions to get the group talking and, like, you know, engaged in a fun conversation, and that specificity helps. One thing that I was just wondering about is the value of meeting every day in a sync kind of format, and I'm curious if you think that is important to you. If you have been on other teams that don't meet every day, maybe they have, like, a virtual check-in, right? Like, a virtual reminder to share what they're working on as opposed to meeting synchronously. JOËL: I think I've seen sort of different purposes for sync meetings. Sometimes it's very kind of project-heavy, right? You're talking about the tickets you're working on for today. The reason you're having that is specifically for status updates or because you are blocked, and you want somebody else to help unblock you. So, it's very process-focused. I think that varies team to team, but it can be really helpful. Even I've been on projects where it's maybe me and one other person, and we'll have kind of an informal just call each other up every morning and say, "Hey, here's what I'm working on today. Here's kind of roughly the strategy I plan to take on it. And we'll go back and forth." And for something like that, it inevitably also somewhat turns into a bit of a social call, so that's planning and social. And I think that can be really strong. STEPHANIE: Yeah, I like that a lot. JOËL: That's not necessarily going to be the case for every team, every project, especially with larger teams. And I feel like for something like the Boost Team at thoughtbot, we have a daily sync. We're not all working on the same project. So, I don't want to know about the specific details of the ticket you're working on. I'm more interested in getting just a little bit of face time with the whole of our team to feel a connection. And, you know, maybe if you've got something cool that you want to share, and that can be a win. It can even be a struggle. And we can all kind of empathize, right? That, like, "Oh, I dropped production database this morning, and I'm kind of freaking out," is a totally fine thing to share. But "I am working on ticket 1, 2, 3, 4 to add some text to a part of the page," that's not particularly useful to me in the kind of sync that we have for the thoughtbot Boost Team. STEPHANIE: Yeah, absolutely. I think knowing, like, who the audience is of the meeting and, like, how they might be able to support you or be there for you is helpful in making them feel a little more relevant and personal. And I had mentioned that our Boost daily meetings or daily syncs, you know, are a little too big for people to really get into, you know, sharing a fun, personal anecdote, or whatever. But one thing that I really enjoy is that whoever goes last in giving their update gets to choose the sign-off for everyone. So maybe that's like, okay, we'll just go out on a wave, and we all wave. Or maybe it's, you know, like, making a little heart with your hands. And then there's some folks on the team who go really wild and, you know, come up with something totally unexpected. And I think, you know, that spontaneity is so fun. And we all share it in this collective act of...I'm trying to think of a funny one lately, maybe, like, sinking down into your chair until you disappear from the view [laughs]. That's a good one. JOËL: Sometimes it's those, like, small social rituals that can be really meaningful. STEPHANIE: Absolutely. Do you have a favorite sign-off that you have either requested or have done? JOËL: So, I typically just go for the wave if I'm last because I've not thought about it. But I generally think it's fun to have everybody try to mimic an emoji. So, it might be like, oh, everybody do the, you know, See-No-Evil emoji, or everybody do the party parrot. Those are pretty fun to sign off on. STEPHANIE: Oh yeah, [inaudible 29:15] pausing is good. I think another one I like is, "Everyone do your best impression of a tree." [laughs] JOËL: Sometimes, too, it's fun to do something that's relevant to the particular day. If there's something special happening that day, you get something relevant. I've done before, if it's on a Friday, say, "Everybody do your best Rebecca Black impression." STEPHANIE: Yeah, also excellent. JOËL: Because, you know, it's Friday. STEPHANIE: Yeah, like, a little moment of collective celebration for the weekend. On that note, it's a Friday we're recording this episode. Shall we wrap up and look forward to the weekend? JOËL: [laughter] Fun, fun, fun, fun. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeee!!!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
Joël recently had a fascinating conversation with some friends about the power of celebrating and highlighting small wins in their lives. He talks about bringing this into his work life. May Stephanie interest you in a secret she learned regarding homemade pizza? RubyConf is coming! Who's submitting talks?! It's hekkin scary. Don't fret! Joël and Stephannie are here to help. Today, they discussed submitting a conference talk proposal from start to finish. Sheet pan pizza (https://anewsletter.alisoneroman.com/p/may-we-interest-you-in-a-party-of) RubyConf CFP (https://sessionize.com/rubyconf-2023/) Speakerline.io (https://speakerline.io/) WNB.rb (https://www.wnb-rb.dev/) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we've come here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: I've been having a really interesting conversation with some of my friends recently about the power of celebrating and highlighting small wins in our lives, both in, like, kind of sharing it with each other, like, you know, if something small happens, it's good for me to share it with my friends. But also, where it becomes really cool is where the friend group kind of gets together and celebrates that small win for one person, and how that can be, like, a small step to take, but it's just really powerful and encouraging for a friend group. And I think that applies not just among friends but in a team or other grouping in the workplace. STEPHANIE: That's so fun. How are you celebrating these small wins, like, over text? Is that the main way you're communicating something good that happened? JOËL: It depends on the friend group. I think, like, different friend groups will have, like, a different kind of cadence for the kind of things they do. And do they all hang out together? Do they have a group text, things like that? One of the friend groups I'm a part of, we meet weekly to go climbing at a rock-climbing gym, so that's kind of our hang-out. And [inaudible 01:34], we're there to do stuff at the gym, but it's also a social thing. And it's an opportunity to be like, "Oh, you know, did that thing workout, you know, at work?" "You know, good for you," Or "Did you get this project accepted?" And yeah, when small wins come up, it's a great time to celebrate. STEPHANIE: That's awesome. I think having regular time that you see people and being able to ask them about something that they had mentioned previously is so special and really important to me, like, in bonding and building the relationship. I also love the idea of celebrating milestones. So, this is, I guess, more of a bigger win, but milestones that aren't traditionally celebrated. You know, so, yeah, we'll have, like, a party when someone graduates or someone gets married. But I also have really enjoyed celebrating when someone gets a promotion at work. And, you know, maybe that's not, like, a once-in-a-lifetime thing, but it's still so worthy of going out for dinner or buying them a drink. I also will maybe, like, send my friends a little treat if I know that they did something small but hard for them, right? And sometimes that's even, like, responding to a scary email that they had sitting in their inbox for a while. Yeah, I really love that idea of supporting people, even in the small things in life that they do. JOËL: Yeah, and that's really validating, I think when you've done something hard and then a friend or a colleague reaches out to you. And it's kind of like, hey, I saw that. Good for you. STEPHANIE: How have you been thinking about bringing this into your work life? JOËL: I think it's about being on the lookout for things that other people do. And I think one thing I like to do is kind of publicly calling that out. It sounds like a negative thing, right? But just giving people kind of a public shout-out when they've succeeded at something. I think we're all kind of socialized not to maybe talk too much about accomplishments, especially if they feel kind of small and mundane. Being somebody else, I think, gives you a lot more leeway to say, "Hey, no, Stephanie, I see that you did that thing. And maybe it feels kind of like, oh no, you're just doing your job, but I think that's cool. And I want to, you know, just give you a shout-out in the company Slack channel or something." It doesn't have to be something big. You know, I'm not sending champagne to your home. But having that opportunity to just kind of celebrate something small and say, "Wait a minute, let's pause and acknowledge that you just did something cool." STEPHANIE: Yeah, I was thinking about how that's kind of, like, amplifying the win a little bit. I've definitely done this before, too, when I see someone share a win of theirs, maybe in a smaller Slack channel or kind of a personal level, or even just to me individually. And I really want other people to know that that happened to you and that they, you know, did an awesome job. And so, I have enjoyed, you know, sharing them more publicly on their behalf if they are comfortable with it. JOËL: And I'll say on the other end of that, I think it feels really good to be acknowledged by someone else that you've done something that they recognize. It's fun to share a win with other people because you're excited, but it's doubly fun when somebody else shares it for you. STEPHANIE: I agree. I think one thing that you, Joël, do really well, actually, is sharing your own personal wins in a very casual way. That's something I've always admired about you is how you recognize the small wins for yourself. JOËL: It's taken me, I think, a long time to get to that and find a way where, you know, you are sharing things that are fun for other people to see, things that might be inspiring, things that are kind of cool, and that are not just kind of, like, self-aggrandizing, like, bragging about stuff. It can be a fine line to walk. And, to a certain extent, you're a little bit marketing yourself. But yeah, I think I've kind of hit that right balance. STEPHANIE: Yeah, I think the thing that makes it work is that there's usually, like, a challenge or something that maybe you, like, went through a journey or overcame a little bit. And I think that's what is the inspiring part that makes me feel like, oh, okay, so, like, this is a realistic thing that, you know, Joël went through and, you know, he struggled with it maybe. But then, like, ultimately, you know, had some insights or came out the other side with some learnings. And I like that it's real, right? It's not just, "Hey, like, I did this, like, cool thing." It's like, "I went on this journey." And I find that really motivating when I am in that kind of situation next time. JOËL: There's a power to stories, right? And I think especially when you can make something relatable to other people. So, it's not just like, "Hey, I did a cool thing," which, you know, is also fun. But being able to say, "Hey, I messed up," or "I, you know, had this challenging problem dropped in my lap, and here's the journey I went on to resolve it. Hopefully, it acts a little bit as like a here's a template you could follow if you're ever in that situation." But maybe also a little bit of, like, inspiration for others as well, just being like, hey, Joël, messes up sometimes. So, Stephanie, what is new in your world? STEPHANIE: Speaking of small wins, I have finally perfected our at-home pizza situation for making pizza at home, which I have been struggling with for so long. Because I always was excited by the idea of making pizza and, you know, sometimes we would make our own dough. And sometimes, we would buy store-bought dough, but it never ended up being as crispy and cooked well-done the way that I want it to. It was always, like, a little bit mushy on the inside. The dough wasn't totally baked. And I would inevitably be disappointed when I had been, you know, building that excitement for pizza. And the other week, I found a new recipe to try, and I think it will be my new go-to recipe for making pizza at home. JOËL: I don't know if I'm allowed to ask this on air, but what's the secret? STEPHANIE: The secret? Well, okay, the first secret and/or learning that I've gathered is to not put as much sauce, cheese, and toppings as you think you want to because that's definitely what contributes to the under-doneness of the dough. But I pivoted to trying a more grandma-style crust that is kind of more like focaccia; really, you know, it involves a lot of olive oil. And you're cooking it for a while on pretty high heat to ensure the crispness and, you know, that it's cooked through. And, I mean, I love focaccia bread, so I don't mind it as, you know, the base of my pizza. It is a bit different from, you know, other kinds of pizzas. And if we had, like, a really, you know, fancy pizza oven to do the, like, super high heat, like, Neapolitan-style deal, I would also really enjoy that. But you know what? That's just not the reality of my home kitchen. So, I have really been enjoying this pizza recipe by Alison Roman that I will link in the show notes. But yeah, it has really changed my at-home pizza game. And I hopefully won't have any of my, you know, soggy dough bottom problems anymore. JOËL: So, you mentioned just kind of offhand, like, oh yeah, you know, the crust is just kind of, like, how you make focaccia. It sounds like you've made focaccia yourself before. STEPHANIE: I have made focaccia at home, and so I think applying it to Pizza was a real, like, light bulb moment for me. But, you know, it's not, like, totally effortless. But I think it's a lot more forgiving than other types of bread and, therefore, other types of pizza crust. And the one really enjoyable thing about making focaccia is there's a step where you use your fingers, and you're kind of holding your hands like you're playing a piano. And you, like, press into the dough after it has risen a little bit to create dimples and, you know, lets the oil kind of seep into the little holes. And it's very satisfying. It's a very good feeling. JOËL: The kind of the tactile aspect of it? STEPHANIE: Yeah, exactly. It's very fun. [chuckles] So, yeah, it's just an added bonus to my pizza adventures. JOËL: A win on top of a win. We'll take it. So, there's some news in the Ruby community this week because RubyConf has just opened their CFP, their call for proposals. And so, they're asking for people to submit their ideas for conference talks, and if you're lucky, you get picked to speak at the conference. And, Stephanie, I know that over the course of a year, you have a document where you collect conference talk ideas so that you have ideas to work on when the CFP comes around. Are you looking at any of them to potentially submit to RubyConf this year? STEPHANIE: Joël, I have to be honest with you; so far, I only have one idea on that list. [laughs] But that is one that I suppose could eventually become a conference talk proposal. So, when I heard the news, I definitely went down the rabbit hole of revisiting that idea and kind of starting to think about if it's something I wanted to pursue. I think the answer is yes. I definitely got a big push of motivation when I was like, oh, it's open. Like, now I can just get started if I want to. And then I was like, well, it's open for a month, so I could also just sit on it a little longer, you know, put it aside and revisit it when I have a little more time. But yeah, I was pretty excited because I think it gave me the motivation I needed to really think a little more deeply about this idea that I have. Otherwise, I think it would have continued to sit half-baked in my document for a long time. JOËL: And just for all of our listeners, the CFP just opened on July 12th, and it closes on August 20th. So, if you are listening and it's before August 20th, you still have a shot to submit your idea to be a speaker. STEPHANIE: Something that I've talked about with my other friends who enjoy speaking at conferences is how they come up with proposals, and I found that we all have different approaches. And I am really interested in digging into this further with you. But I realized that, for me, I really struggle with just, like, throwing out ideas and submitting them before I feel really confident that it's something that I have interesting things to say really, or, like, kind of adding a new perspective, or maybe approaching a topic that hasn't been approached before. I feel sometimes a bit hindered by my process, where I need to feel really confident before submitting something. Because a friend of mine she was telling me that her approach is to submit CFP for topic ideas that she wants to explore further. So, maybe it is something that she doesn't know a lot about yet, and she's using this process to learn more and dive deeper, and that, you know, gives her a reason to do that, whereas that seems really scary to me. JOËL: That's really interesting because it sounds like kind of an underlying motivation for your friend for submitting these talks is curiosity, exploration. And thinking back to myself, I think I usually submit ideas that have me excited or passionate, so that's kind of my underlying motivation for a talk. What would you say is maybe your underlying motivation when you're pitching an idea? STEPHANIE: Yeah, I think, for me, it is impact and, like, having an impact, especially for something that I've struggled with and wanting to share my experience and, hopefully, sharing something where other people can relate to. It's funny you mentioned that your motivators are, you know, excitement and passion. Because another person that I kind of had this conversation with mentioned that she writes talks based on experiences that have been very aggravating [chuckles] and painful for her. So, that ends up being, you know, a big motivator because she's so frustrated. [laughs] And, you know, wants to share this journey that she went on from a point of, I guess, maybe similar to me, like, making it easier for someone else who might find themselves struggling with the same problem. JOËL: I kind of like the idea of taking that to an extreme, and you're, like, rage submitting. STEPHANIE: Yeah, I feel like there would just be an infinite number [laughs] of topics that you could come up with in that case. JOËL: Like, I'm so angry at this bug. It cost me a week of my life. And now, it is going to get the spotlight on it at RubyConf. And I get to share that moment with everyone, express a lot of emotions, and, hopefully, save everyone else from having to do the same thing I did. STEPHANIE: Yeah. Or this terrible bug cost me a week of my life, and now you all get to hear about it. [laughter] Let me tell you -- JOËL: Yes. STEPHANIE: Exactly all the problems that I had to deal with. JOËL: And, honestly, as a narrative, it kind of works, right? There are different types of talks. Sometimes you go to a talk because you really want to learn a deep topic. Sometimes I just want to go and listen to, like, a good horror story. If someone's a good storyteller, like, yes, there are lessons I can take away from it, and I can be like, okay, this is what I can do. And I heard Stephanie talk about this bug, and so I'm going to use inspiration from that the next time I hit a bug. But sometimes it's also just good to, like, go there and sit and be, like, yes, I've been there. Yeah, kind of following along with the story and, you know, kind of the ups and downs because it is so relatable. STEPHANIE: Yeah. And I like that you mentioned that there are different types of talks that leave the audience, you know, with different things. Because I know some people who have been interested in speaking in the past maybe feel a bit hesitant to because they don't think they have something to say, or, like, they don't have something to share that other people might find interesting. And to that, I really believe that everyone has something that they are knowledgeable about and something that they can bring to others that is valuable. Even if it's not for every single person at the conference if you give a talk that is meaningful to a handful of people, right? Especially because, you know, there's people of all different kinds of levels at these conferences. Those are really important too. In fact, I think it can be even more powerful because they are targeting a specific audience. JOËL: And I think you've hit on a key point, that is, it's great when you're building the talk, but even when you're pitching the idea is, who is this talk for? Who is the audience for this talk? And if the audience is whoever shows up at the conference center, maybe you need to workshop a little bit more. STEPHANIE: Yeah, because one thing can't really be for everyone. JOËL: Right. You're kind of diffusing its impact at that point. You were talking about how sometimes it's difficult to take an idea, flesh it out, and submit it until you're feeling, like, 100% confident about it. I'm curious how the transition goes from kind of the earlier phase of, like, you have a document, and I assume these are, like, bullet points with, like, one sentence, or maybe even just title idea. How does it go from bullet point to multiple paragraphs that might be submittable? STEPHANIE: Yeah, that's a good question. I think it starts as a bullet point because maybe I notice something that caused me pain or caused a teammate pain, and maybe we had, like, kind of an interesting discussion about it. And, yeah, I write it down as something to explore further as, like, is this an idea that can be a little broader in scope, can have a few more applications beyond this particular instance that sparked it? And so, maybe from there, I will think about, like, okay, like, the pain point that I jotted down was coupling and tests, right? And let me go, you know, jog through my memory of other times where I kind of felt a similar thing or was doing some code review and also noted a similar problem. And I think if I am able to find enough, like, supporting examples that might go along with this, for me, it's really a feeling. [laughs] Then I'll try to extract that a little further and come up with a theme, right? A theme that's a little more encompassing because what I hope to do is to be able to come up with some kind of takeaway that can be a strong thesis for a conference proposal. JOËL: And that's kind of how conference proposals work, right? There's a few different sections you have to fill out. But the really important one is the abstract, which is usually just a few sentences. It's character limited. And that's what is got to sell your talk both to the committee, but then also, that's what's going to be publicly viewable. And so, that's what's going to get people excited to show up at your conference room. So, my kind of secret trick for writing a proposal is to do the abstract last. Even though it's that first section on the form, I struggle to write a compelling abstract. And so, I'll go through and fill out some of the other fields that are only for the committee, and there'll be, you know, a lot of detail in there. And then, sometimes, I find that I put, like, really good compelling sentences in there, and I'll pull them out and put them in the abstract and kind of use that to start. But those other sections, like pitch and all that I think they're a great place to start because you get to go a little bit more into detail. And you can talk about here are the themes I want to address. Here are maybe the examples I'm going to be building around. Here's the audience that I want to speak to. STEPHANIE: Audience is interesting for me because I tend to write the kind of talks that I wish I had watched earlier or, like, what really speaks to me. In fact, one of my first conference talks was literally called The Intro to Abstraction I Wish I'd Received. [laughs] So, that is a good place for me to start, is thinking about like, well, like, who was I at the time? Like, what kind of developer was I at the time that I, like, really needed this information or really wished for this information? And similarly, I had mentioned, you know, like, maybe my ideas are coming from conversations I've had with other people. So, I'm imagining those other people, and I'm asking myself, like, who are they? Like, where are they in their development careers? And is there a specific demographic or audience persona that kind of fits them, and, you know, usually there is, right? And what is nice is I can kind of go to them as well and be like, "Hey, like, I have this idea. Do you think this would be helpful for you? Or is this something you would be interested in watching?" And that at least helps me ground it in an audience that is real to me as opposed to kind of trying to imagine who might show up without a clear idea, like, of what they might get a takeaway or, like, be wanting in a conference talk. JOËL: Would it be fair to say that when you're coming up with an idea for a presentation, the audience you have in mind is you or maybe a particular version of you, so you two years ago or you five years ago? STEPHANIE: Yeah, I think that's a really compelling way for me to write these because, you know, I almost think it kind of goes back to the idea that everyone has something to say, right? It's like I have something to say to me, my past self. And I believe that other people, you know, are in that position as well. And so, that's been my approach. But I'm curious about yours because I think the types of talks that you write are maybe less about, like, what you wished you had learned earlier and more for a different kind of audience. JOËL: Yeah, I think they are...I start with a topic that I'm excited about. And then, sometimes, I have to find what element of it that I want to pull out because it can be kind of a whole kind of cloud of themes, and I have to pick one to commit to. Depending on the one I commit to and the approach I want to take, it will define the audience that...or vice versa. I can say, okay, this is specifically for this audience, and that will show how I want to approach it. So, for example, I gave a talk at RailsConf this past spring on the math every programmer needs, talking a little bit about discrete math and how it's applicable in day-to-day programming. And I think I very quickly came to the realization that I wanted this talk to be for people who had never done a formal, like, discrete math class, likely people who don't have a traditional, like, CS background. And so, once I knew this is the audience I'm speaking to, that really shaped how I pitched the talk, what elements I want to bring in, what examples I'm using, what do I want to emphasize during this talk. Finding that audience really helped that proposal come together. Even though I knew...before I found the audience, I knew I wanted to talk about discrete math and how cool and relevant it was to day-to-day programming. But that's not enough. I needed to really fit it to an audience. STEPHANIE: Yeah, I have two thoughts about this. One was that when you were writing the proposal for this talk, I remember you had shared a bunch of your different ideas about the topic to your co-workers. And it was almost kind of, like, a buffet of topics. And you were asking for feedback about, like, hey, like, what is interesting to you? Like, what would be, like, helpful for you to know? And I think that ended up really helping you focus on, like, what your audience would want. But I'm curious, do you recall, like, how you decided that you wanted to target people who didn't have that traditional CS background? Like, why was that important to you? JOËL: I think I'm generally most excited about taking some, like, larger technical insights and bringing them to people who maybe have some of the intuition but don't always know why the things they do work the way they do and kind of bridging a little bit of that, like, practical, theoretical gap. That's the space that I'm probably most excited about when it comes to sharing and teaching, helping people go from things that are really practical and then just throwing just enough theory at them. But keeping it really grounded so that they can kind of hit the next level of where they want to be. Because that's an area that I think I thrive in, an area that gets me most excited to share about. And so, I think, naturally, I'm kind of moving in that direction. But also, like you said, it's talking to other people and seeing, like, what are the elements that are interesting to you? And then, like, once you start seeing some of these, it's like, okay, well, what is exciting in talking about Boolean algebra? Do I want to go really deep on some of the theory? Do I want to say, you know, if someone has a vague notion of this because they've been writing code for several years but don't know the theoreticals behind it? That interaction, I think, was more compelling to me. STEPHANIE: Got it. It's almost like knowledge sharing at just this really high level, or, like, at a really large scale. I like that a lot. JOËL: So, you highlighted something interesting, and that is that writing a proposal doesn't have to be a solo activity, and getting feedback on ideas can totally transform your proposal. Do you find that you reach out to a lot of people to get feedback on your proposals? And what does that look like in practice? STEPHANIE: Oh yeah, I definitely need someone to rubber-duck an idea for me. [laughs] JOËL: So, even at the idea stage. So, you've got that topic sentence or whatever, and then you say, "Someone, can you sit down with me, and we'll just talk through places this might go?" STEPHANIE: Yeah. I have found that really helpful for me. Otherwise, I think I get a little too precious about it, right? If I've just been working on it by myself. And then it feels really scary to submit it and be like, okay, I don't know if this is any good. It might get rejected. But the first time that I did a conference talk, WNB.rb, the women and non-binary Ruby group I'm in, they had organized a CFP working group channel. And so, there were, you know, a handful of people, some of them writing conference talks for the first time, some of them having done it before, just getting together and holding each other accountable, and checking in and asking for feedback. And, yeah, I think finding other people who either have done it before. I've also, you know, reached out to people whose conference talks I loved and felt really inspired by. And if they were available, like, kind of asking them how to get started. But also, like, peer support as well, other people doing it for the first time can be really important in just making it feel a little more manageable, a little less lonely. I think there are, like, more people out there who are interested in dipping their toe in conference speaking than one might think because it can definitely feel very overwhelming. But with a support group, I think it makes it a lot easier. JOËL: So, you've gotten feedback. You've gotten support. You've put this idea together. You're feeling pretty confident. You hit that submit button. And now you can't take it back. [laughs] How does that feel at that point? STEPHANIE: Terrifying. [laughter] Like, for me, I have to exercise it from my mind and not think about it, not dwell on it at all. And like, ideally, you know, when I hear back, I will have forgotten all about it so that, you know, I didn't spend the whole month or however many weeks, like, ruminating about whether or not it was accepted. Yeah, I really struggle with that part, I think, because I, yeah, have a hard time with rejection, you know, I'm just going to say it. [laughs] And, you know, it's hard for me not to take it personally. But I think that's actually one area that I want to get better at is to feel a little less, like, personally attached. And I think working with others helps me with that because it's not just something I've, you know, like, squirreled away and feel very attached to. Working with others and then, like, hopefully, coming up with other ideas along the way, right? Within conversations that we have that might spark ideas for the future. So, knowing that if this one doesn't end up being submitted, there's always next time. There's always another conference season. And also, you know, celebrating others when their conference talks do get accepted that is also really buoying because it helps me direct that energy into wanting to celebrate my friends and inspiring me for next time. Joël, I know you oftentimes submit more than one proposal, and I'm wondering if that helps with those feelings of being too attached to a topic idea or, you know, worrying about whether they will be accepted. JOËL: I think it definitely helps with the attachment thing that I've not kind of put all of my work and all of my...like, pinned all of my hopes on one topic idea. Sometimes it can hurt, you know, if you've got, like, you know, two or three and, like, you just get multiple rejection notices in a day. That kind of sucks sometimes. But I think, in some ways, yes, it does help with that feeling of rejection because you've not tied yourself emotionally so much to a single idea that has to, like, succeed or fail. STEPHANIE: Do you then submit those ideas to other conferences? JOËL: The ones that get rejected? Yes. I've definitely resubmitted ideas. In fact, I plan to resubmit a rejection to RubyConf this year, so we'll see how that goes. Actually, now that I think of it, that could be a really fun opening line for a talk. Like, let's say it gets accepted. And, like, you know, you're on the stage, and you open it, and you're just like, "This talk got rejected." That'd be a fun intro. STEPHANIE: Yeah, it would be. I think, oftentimes, you know, it's not always even about the idea itself, right? It's just about maybe the theme of the conference that year, and what they were looking for, and the direction they wanted to go. And there are other conferences or other another year, right? Where maybe there isn't another talk that touches on the same, like, area. And that will be the opportunity that it is a fit for the conference. JOËL: Yeah, definitely. It is a little bit haphazard to get in. And just because your talk gets rejected does not mean it's a bad idea. It just means that it wasn't the best fit for that conference at that time. STEPHANIE: I actually want to plug a website, speakerline.io, where people can post all of their, you know, proposals that they've submitted, whether they were accepted or rejected. And I found that resource really helpful in, you know, just knowing that, like, very good ideas get rejected sometimes, and that's okay. As well as, you know, kind of trying to get a sense of, you know, for the ones that were accepted, okay, like, what about these proposals really stood out or, like, really shine? And how might I get some inspiration from that to incorporate next time around? JOËL: So, you've submitted a proposal. Terrifying. You're trying to not think about it for a couple of weeks, assuming you're submitting ahead a couple of weeks, I don't know. Are you a last-minute kind of submitter? STEPHANIE: I'm a probably two or three days before the deadline kind of submitter. JOËL: So, you've submitted the talk two or three days to the deadline. I guess, like, a couple of weeks after that to get review. And then, you get that notification that says, you know, you've got a response on your talk from the committee. Are you the kind of person that, like, drops everything and immediately looks at it? Do you kind of, like, wait for, like, maybe a moment where you're, like, more in a good zone emotionally before you open that email to find out if you're accepted or rejected? What's your strategy? STEPHANIE: Oh God, I don't think I have the willpower to wait until I'm, you know, in an emotionally good state. I will just click on that thing. And yeah, I think, I mean, having been on the receiving end of accepting those rejections and once waitlisted, [laughs] which was a real doozy because it's like, great, like, now I have to write a talk. But, like, I don't know if it will actually be given or not. I think this is also where the support group really shines as well because maybe some of my other friends are also sharing the results and making it okay, like, sharing a rejection, right? And I think it's nice to just have, like, an outlet for that, whatever the outcome is, and not having to just, like, sit alone in either the sadness or the happiness, right? Like, we're talking about celebrating small wins. Like, it really is even more special when someone else can validate your success. JOËL: Have you ever had to navigate kind of, like, slight feelings of jealousy where it's, like, another friend gets in? Or maybe somebody else gets in with, like, your topic, and their talk got picked instead of yours? STEPHANIE: Yeah, for sure. I think it's totally natural and human. I think one nice thing, though, is that there are so many conferences all of the time. You know, this is not a once-in-a-lifetime situation, right? And maybe the next conference, you know, the people who submit will be different, the people who review will be different. And you've kind of already done the hard part of writing the thing. I actually was just thinking about a few of my friends are writers, and the submission process for them, you know, of spinning a book proposal or short stories for, like, a magazine or something like that, it's, like, fraught with rejections. And they've really built that muscle of acceptance and, like, knowing that it's not a reflection of their value, and building the resilience to keep trying. And so, yeah, I think definitely going through that process has helped me feel a little bit more comfortable with that, not completely, but I guess it's like exposure therapy, [laughs], isn't it? JOËL: I think that the not helpful answer here is that it gets better when you've given more talks. When you're trying to break in and give your first talk, right? It is such a big deal. And, you know, the high of getting accepted is just, you know, mountain top. But the feelings of rejection are also similarly intense. As opposed to when you've done a few, then it's like, you know what? Win some, lose some. And it's much easier to move on. STEPHANIE: I think another suggestion that I might have would be to maybe start smaller, right? Even giving a talk at work for your co-workers, or even the next step is giving a talk at your local meetup or then a small regional conference. There are so many in-between steps, I think, that exist that bestow the benefits of giving a conference talk, and meeting new people, and feeling good about the impact you're having beyond some of the bigger, more traditional conferences. So, if that does seem really scary or, you know, maybe you've given it a shot and feel a little bit demoralized from trying again, there is a group out there who will benefit and be interested in hearing what you have to say. JOËL: That's a really important reminder because just because a conference rejected your talk doesn't mean that it's a bad idea. And yes, you can shop it around and bring it to other conferences, but maybe think about other venues for the idea. You've already done the hard work of crafting a pitch, so maybe turn it into a blog post and share it that way. Maybe turn it into a pitch to be a guest on a podcast that you enjoy. Podcasts that do weekly guests are constantly looking for interesting people to talk to. And you've kind of, like, done all the work for them, where you can say, "Hey, here's the thing I'm an expert on. Ask me questions about this." And most places will gladly bring you on. STEPHANIE: Yeah, I like to think of conference talks as really, like, a supplement of what you're learning and investing in in your career, right? You know, it is nice to be able to share all of those things in a perfectly wrapped package. But also, there are so many different ways for that to manifest. And there are people who know that speaking is not for them and really focus on writing, and that's, like, their avenue. But yeah, it's not...I don't think it's, like, a pinnacle of, like, something you have to do in your career at all. It's just something that can be fun. JOËL: Yeah, and sharing takes many different forms. It can be a talk in a conference room, but it can just as easily turn into maybe some kind of video, some kind of written work. Like I said, it could be an interview on a podcast. There are so many different ways that you can share your ideas. And just because it didn't fit in one place, now that you've done the work to kind of polish that gem a little bit, oftentimes, it's very little additional work to just convert it to a different form. STEPHANIE: Yeah, I like what you just said about polishing a gem. Really, I think the value for me is having a channel to funnel and reflect on my experiences, and, you know, conference talks happen to be, like, one form of that for me. But I hate to say it's about the journey, not the destination, but sometimes it is. And, yeah, I think everyone kind of has to, like, figure that out for themselves. JOËL: That being said, sometimes the destination is pretty exciting. And when you open that email that says, "Congratulations, your talk has been accepted," wow, what a rush. STEPHANIE: On that note, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeeee!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
It's updates on the work front today! Stephanie was tasked with removing a six-year-old feature flag from a codebase. Joël's been doing a lot of small database migrations. A listener question sparked today's main discussion on gerunds' interesting relationship to data modeling. Episode 386: Value Objects Revisited: The Tally Edition (https://www.bikeshed.fm/386) RailsConf 2017: In Relentless Pursuit of REST by Derek Prior (https://www.youtube.com/watch?v=HctYHe-YjnE) REST Turns Humans Into Database Clients (https://chrislwhite.com/rest-contortion/) Parse, don't validate (https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/) Wikipedia Getting to Philosophy (https://en.wikipedia.org/wiki/Wikipedia:Getting_to_Philosophy) Transcript: JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. STEPHANIE: And I'm Stephanie Minn. And together, we're here to share a bit of what we've learned along the way. JOËL: So, Stephanie, what's new in your world? STEPHANIE: So, this week, I've been tasked with something that I've been finding very fun, which is removing a six-year-old feature flag from the codebase that is still very much in use in the sense that it is actually a mechanism for providing customers access to a feature that had been originally launched as a beta. And that was why the feature flag was introduced. But in the years since, you know, the business has shifted to a model where you have to pay for those features. And some customers are still hanging on to this beta feature flag that lets them get the features for free. So one of the ways that we're trying to convert those people to be paying for the feature is to, you know, gradually remove the feature flag and maybe, you know, give them a heads up that this is happening. I'm also getting to improve the codebase with this change as well because it has really been propagating [laughs] in there. There wasn't necessarily a single, I guess, entry point for determining whether customers should get access to this feature through the flag or not. So it ended up being repeated in a bunch of different places because the feature set has grown. And so, now we have to do this check for the flag in several places, like, different pages of the application. And it's been really interesting to see just how this kind of stuff can grow and mutate over several years. JOËL: So, if I understand correctly, there's kind of two overlapping conditions now around this feature. So you have access to it if you've either paid for the feature or if you were a beta tester. STEPHANIE: Yeah, exactly. And the interesting thought that I had about this was it actually sounds a lot like the strangler fig pattern, which we've talked about before, where we've now introduced the new source of data that we want to be using moving forward. But we still have this, you know, old limb or branch hanging on that hasn't quite been removed or pruned off [chuckles] yet. So that's what I'm doing now. And it's nice in the sense that I can trust that we are already sending the correct data that we want to be consuming, and it's just the cleanup part. So, in some ways, we had been in that half-step for several years, and they're now getting to the point where we can finally remove it. JOËL: I think in kind of true strangler fig pattern, you would probably move all of your users off of that feature flag so that the people that have it active are zero, at which point it is effectively dead code, and then you can remove it. STEPHANIE: Yeah, that's a great point. And we had considered doing that first, but the thing that we had kind of come away with was that removing all of those customers from that feature flag would probably require a script or, you know, updating the production data. And that seemed a bit riskier actually to us because it wasn't as reversible as a code change. JOËL: I think you bring up a really interesting point, which is that production data changes, in general, are just scarier than code changes. At least for me, it feels like it's fairly easy generally to revert a code change. Whereas if I've messed up the production database, [laughs] that's going to be unpleasant few days. STEPHANIE: What's interesting is that this feature flag is not really supported by a nice user interface for managing it. And so, we inevitably had to do a more developer-focused solution to remove these customers from being able to access this feature. And so, the two options, you know, that we had available were to do it through data, like I mentioned, or do it through that code change. And again, I think we evaluated both options. But what's kind of nice about doing it with the code change is that when we eventually get to delete those feature flag records, it will be really nice and easy. JOËL: That's really exciting. One thing that's different about kind of more mature projects is that we often get to do some kind of change management, unlike a greenfield app where you just get to, oh, let's introduce this new thing, cool. Oftentimes, on a more mature project, before you introduce the new thing, you have to figure out, like, what is the migration path towards that? Is that a kind of work that you enjoy? STEPHANIE: I think this was definitely an exercise in thinking about how to break this down into steps. So, yeah, that change management process you mentioned, I, like, did find a lot of satisfaction in trying to break it up, you know, especially because I was also thinking that you know, maybe I am not able to see the complete, like, cleanup and removal, and, like, where can someone pick up after me? In some ways, I feel like I was kind of stepping into that migration, you know, six years [laughs] in the making from beta to the paid product. But I think I will feel really satisfied if I'm able to see this thing through and get to celebrate the success of saying, hey, like, I removed...at this point, it's a few hundred lines of code. [laughs] And also, you know, with the added business value of encouraging more customers to pay for the product. But I think I also I'm maybe figuring out how to accept like, okay, like, how could I, like, step away from this in the middle and be able to feel good that I've left it in a place that someone else could see through? JOËL: So you mentioned you're taking this over from somebody else, and this has been kind of six years in the making. I'm curious, is the person who introduced this feature flag six years ago are they even still at the company? STEPHANIE: No, they are not, which I think is pretty typical, you know, it's, like, really common for someone who had all that context about how it came to be. In fact, I actually didn't even realize that the feature flag was the original beta version of the product because that's not what it's called. [laughs] And it was when I was first onboarding onto this project, and I was like, "Hey, like, what is this? Like, why is this still here?" Knowing that the canonical, you know, version that customers were using was the paid version. And the team was like, "Oh, yeah, like, that's this whole thing that we've been meaning to remove for a long time." So it's really interesting to see the lifecycle, like, as to some of this code a little bit. And sometimes, it can be really frustrating, but this has felt a little more like an archaeology dig a little bit. JOËL: That sounds like a really interesting project to be on. STEPHANIE: Yeah. What about you, Joël, what's new in your world? JOËL: So, on my project, I've been having to do a lot of small database migrations. So I've got a bunch of these little features to do that all involve doing database migrations. They're not building on each other. So I'm just doing them all, like, in different feature branches, and pushing them all up to GitHub to get reviewed, kind of working on them in parallel. And the problem that happens is that when you switch from one branch where you've run a migration to another and then run migrations again, some local database state persists between the branch switch, which means that when you run the migrations, then this app uses a structure.sql. And the structure.sql has a bunch of extra junk from other branches you've been on that you don't want as part of your diff. And beyond, like, two or three branches, this becomes an absolute mess. STEPHANIE: Oh, I have been there. [laughs] It's always really frustrating when I switch branches and then try to do my development and then realize that I have had my leftover database changes. And then having to go back and then always forgetting what order of operations to do to reverse the migration and then having to re-migrate. I know that pain very well. JOËL: Something I've been doing for this project is when I switch branches, making sure that my structure SQL is checked out to the latest version from the main branch. So I have a clean structure SQL then I drop my local database, recreate an empty one, and run a rake db:schema:load. And that will load that structure file as it is on the main branch into the database schema. That does not have any of the migrations on this branch run, so, at that point, I can run a rake db:migrate. And I will get exactly what's on main plus what gets generated on this branch and nothing else. And so, that's been a way that I've been able to kind of switch between branches and run database operations without getting any cross-contamination. STEPHANIE: Cross-contamination. I like that term. Have you automated this at all, or are you doing this manually? JOËL: Entirely manually. I could probably script some of this. Right now...so it's three steps, right? Drop, create, schema load. I just have them in one command because you can chain Unix commands with a double ampersand. So that's what I'm doing right now. I want to say there's a db:reset task, but I think that it uses migrate rather than schema load. And I don't want to actually run migrations. STEPHANIE: Yeah, that would take longer. That's funny. I do love the up arrow key [laughs] in your terminal for, you know, going back to the thing you're running over and over again. I also appreciate the couple extra seconds that you're spending in waiting for your database to recreate. Like, you're paying that cost upfront rather than down the line when you are in the middle of doing [laughs] what you're trying to do and realize, oh no, my database is not in the state that I want it to be for this branch. JOËL: Or I'm dealing with some awful git conflict when trying to merge some of these branches. Or, you know, somebody comments on my PR and says, "Why are you touching the orders table? This change has nothing to do with orders." I'm like, "Oh, sorry, that actually came out of a different thing that I did." So, yep, keeping those diffs small. STEPHANIE: Nice. Well, I'm glad that you found a way to manage it. JOËL: So you mentioned the up arrow key and how that's really nice in the terminal. Something that I've been relying on a lot recently is reverse history search, CTRL+R in the terminal. That allows me to, instead of, like, going one by one in order of the history, filter for something that matches the thing that I've written. So, in this case, I'll hit CTRL+R, type, you know, Rails DB or whatever, then immediately it shows me, oh, did you want this long command? Hit enter, and I'm done. Even if I've done, you know, 20 git commands between then and the last time I ran it. STEPHANIE: Yeah, that's a great tip. So, a few weeks ago, we received a listener question from John, and he was responding to an episode where I'd asked about what the grammatical term is for verbs that are also nouns. He told us about the phrase, a verbal noun, for which there's a specific term called gerund, which is basically, in English, the words ending in ING. So, the gerund version of bike would be biking. And he pointed out a really interesting relationship that gerunds have to data modeling, where you can use a gerund to model something that you might describe as a verb, especially as a user interaction, but can be turned into a noun to form a resource that you might want to introduce CRUD operations for in your application. So one example that he was telling us about is the idea of maybe confirming a reservation. And, you know, we think of that as an action, but there is also a noun form of that, which is a confirmation. And so, confirmation could be a new resource, right? It could even be backed at the database level. And now you have a simpler way of representing the idea of confirming a reservation that is more about the confirmation as the resource itself rather than some kind of append them to a reservation itself. JOËL: That's really cool. We get to have a crossover between grammar terms and programming, and being able to connect those two is always a fun day for me. STEPHANIE: Yeah, I actually find it quite difficult, I think, to come up with noun forms of verbs on my own. Like, I just don't really think about resources that way. I'm so used to thinking about them in a more tangible way, I suppose. And it's really kind of cool that, you know, in the English language, we have turned these abstract ideas, these actions into, like, an object form. JOËL: And this is particularly useful when we're trying to design RESTful either APIs or even just resources for a Rails app that's server-rendered so that instead of trying to create all these, like, extra actions on our controller that are verbs, we might decide to instead create new resources in the system, new nouns that people can do the standard 7 to. STEPHANIE: Yes. I like that better than introducing custom controller actions or routes that deviate from RESTful conventions because, you know, I probably have seen a slash confirm reservation [laughs] URL. And, you know, this is, I think, an interesting way of avoiding having too many of those deviating endpoints. JOËL: Yeah, I found that while Rails does have support for those, just all the built-in things play much more nicely if you're restricting yourself to the classic seven. And I think, in general, it's easier to model and think about things in a Rails app when you have a lot of noun resources rather than one giant controller with a bunch of kind of verb actions that you can do to it. In the more formal jargon, I think we might refer to that as RESTful style versus RPC style, a Remote Procedure Call. STEPHANIE: Could you tell me more about Remote Procedure Calls and what that means? JOËL: The general idea is that it's almost like doing a method call on an object somewhere. And so, you would say, hey, I've got an account, and I want to call the confirm method on it because I know that maybe underlying this is an ActiveRecord account model. And the API or the web UI is just a really thin layer over those objects. And so, more or less, whatever your methods on your object are, can be accessed through the API. So the two kind of mirror each other. STEPHANIE: Got it. That's interesting because I can see how someone might want to do that, especially if, you know, the account is the domain object they're using at the, you know, persistence layer, and maybe they're not quite able to see an abstraction for something else. And so, they kind of want to try to fit that into their API design. JOËL: So I have a perhaps controversial opinion, which is that the resources in your Rails application, so your controllers, shouldn't map one-to-one with your database tables, your models. STEPHANIE: So, are you saying that you are more likely to have more abstractions or various resources than what you might have at the database level? JOËL: Well, you know what? Maybe more, but I would say, in general, different. And I think because both layers, the controller layer, and the model layer, are playing with very different sets of constraints. So when I'm designing database tables, I'm thinking in terms of normalization. And so, maybe I would take one big concept and split it up into smaller concepts, smaller tables because I need this data to be normalized so that there's no ambiguity when I'm making queries. So maybe something that's one resource at the controller layer might actually be multiple tables at the database layer. But the inverse could also be true, right? You might have, in the example that John gave, you know, an account that has a single table in the database with just a Boolean field confirmed yes or no. And maybe there's just a generic account resource. But then, separately, there's also a confirmation resource. And so, now we've got more resources at the controller layer than at the database layer. So I think it can go either way, but they're just not tightly coupled to each other. STEPHANIE: Yeah, that makes sense. I think another way that I've seen this manifest is when, like you said, like, maybe multiple database tables need to be updated by, you know, a request to this endpoint. And now we get into [chuckles] what some people may call services or that territory of basically something. And what's interesting is that a lot of the service classes are named as verbs, right? So order, creator. And, like, whatever order of operations that needs to happen on multiple database objects that happens as a result of a user placing an order. But the idea that those are frequently named as verbs was kind of interesting to me and a bit of a connection to our new gerund tip. JOËL: That's really interesting. I had not made that connection before. Because I think my first instinct would be to avoid a service object there and instead use something closer to a form object that takes the same idea and represents it as a noun, potentially with the same name as the resource. So maybe leaning really heavily into that idea of the verbal noun, not just in describing the controller or the route but then also maybe the object backing it, even if it's not connecting directly to a database table. STEPHANIE: Interesting. So, in this case, would the form object be mapped closer to your controller resource? JOËL: Potentially, yes. So maybe I do have some kind of, like, object that represents a confirmation and makes it nicer to render the confirmation form on the edit page or the new page. In this case, you know, it's probably just one checkbox, so maybe it's not worth creating an object. But if there were multiple fields, then yes, maybe it's nice to create an in-memory object that has the same name as the resource. Similar maybe for a resource that represents multiple underlying database tables. It can be nice to have kind of one object that represents all of them, almost like a facade, I guess. STEPHANIE: Yeah, that's really interesting. I like that idea of a facade, or it's, like, something at a higher level representing hopefully, like, some kind of meaning of all of these database objects together. JOËL: I want to give a shout-out to talk from a former thoughtboter, Derek Prior—actually, former Bike Shed host—from RailsConf 2017 called In Relentless Pursuit of REST, where he digs into a lot of these concepts, particularly how to model resources in your Rails app that don't necessarily map one to one with a database table, and why that can be a good thing. Have you seen that talk? STEPHANIE: I haven't, but I love the title of it. It's a great pun. It's very evocative, I think because I'm really curious about this idea of a relentless pursuit. Because I think another way to react to that could be to be done with REST entirely and maybe go with something like GraphQL. JOËL: So instead of a relentless pursuit, it's a relentless...what's the opposite of pursuing? Fleeing? STEPHANIE: Fleeing? [laughs] I like how we arrived there at the same time. Yes. So now I'm thinking of I had mentioned a little bit ago on the show we had our spicy takes Lightning Talks on our Boost Team. And a fellow thoughtboter, Chris White, he had given a talk about Why REST Is Not the Best and for -- JOËL: Also, a great title. STEPHANIE: Yes, also, a great title. JOËL: I love the rhyming there. STEPHANIE: Yeah. And his reaction to the idea of trying to conform user interactions that don't quite map to a noun or an obvious resource was to potentially introduce GraphQL, where you have one endpoint that can service really anything that you can think of, I suppose. But, in his example, he was making the argument that human interactions are not database resources, right? And maybe if you're not able to find that abstraction as a noun or object, with GraphQL, you can encapsulate those ideas as closer to actions, but in the GraphQL world, like, I think they're called mutations. But it is, I think, a whole world of, like, deciding what you want to be changed on the server side that is a little less constrained to having to come up with the right abstraction. JOËL: I feel like GraphQL kind of takes that, like, complete opposite philosophy in that instead of saying, hey, let's have, like, this decoupling between the API layer and the database, GraphQL almost says, "No, let's lean into that." And yeah, you want to traverse the graph of, like, tables under the hood? Absolutely. You get to know the tables. You get to know how they're related to each other. I guess, in theory, you could build a middle layer, and that's the graph that gets traversed rather than the graph of the tables. In practice, I think most people build it so that the API layer more or less has access directly to tables. Has that been your experience? STEPHANIE: That's really interesting that you brought that up. I haven't worked with GraphQL in a while, but I was reading up on it before we started recording because I was kind of curious about how it might play with what we're talking about now. But the idea that it's graphed based, to me, was like, oh, like, that naturally, it could look very much like, you know, an entity graph of your relational database. But the more I was reading about the GraphQL schema and different types, I realized that it could actually look quite different. And because it is a little bit closer to your UI layer, like, maybe you are building an abstraction that is more for serving that as that middle layer between your front end and your back end. JOËL: That's really interesting that you mentioned that because I feel like the sort of traditional way that APIs are built is that they are built by the back-end team. And oftentimes, they will reflect the database schema. But you kind of mentioned with GraphQL here, sometimes it's the opposite that happens. Instead of being driven kind of from the back towards the front, it might be driven from the front towards the back where the UI team is building something that says, hey, we need these objects. We need these connections. Can you expose them to us? And then they get access to them. What has been your experience when you've been working with front ends that are backed by a GraphQL API? STEPHANIE: I think I've tended to see a GraphQL API when you do have a pretty rich client-side application with a lot of user interactions that then need to, you know, go and fetch some data. And you, like, really, you know, obviously don't want a page reload, right? So it's really interesting, actually, that you pointed out that it's, like, perhaps the front end or the UI driving the API. Because, on one hand, the flexibility is really nice. And there's a lot more freedom even in maybe, like, what the product can do or how it would look. On the other hand, what I've kind of also seen is that eventually, maybe we do just want an API that we can talk to separate from, you know, any kind of UI. And, at that point, we have to go and build a separate thing [laughs] for the same data. JOËL: So we've been talking about structuring APIs and, like, boundaries and things like that. I think my personal favorite feature of GraphQL is not the graph part but the fact that it comes with a built-in schema. And that plays really nicely with some typed technologies. Particularly, I've used Elm with some of the GraphQL libraries there, and that experience is just really nice. Where it will tell you if your front-end code is not compatible with the current API schema, and it will generate some things based off the schema. So you have this really nice feedback cycle where somebody makes a change to the API, or you want to make a change to the code, and it will tell you immediately is your front end compatible with the current state of the back end? Which is a classic problem with developing front-end code. STEPHANIE: First of all, I think it's very funny that you admitted to not preferring the graph part of GraphQL as a graph enthusiast yourself. [laughs] But I think I'm in agreement with you because, like, normally, I'm looking at it in its schema format. And that makes a lot of sense to me. But what you said was really interesting because, in some ways, we're now kind of going back to the idea of maybe boundaries blurring because the types that you are creating for GraphQL are kind of then servicing both your front end and your back end. Do you think that's accurate? JOËL: Ooh. That is an important distinction. I think you can. And I want to say that in some TypeScript implementations, you do use the types on both sides. In Elm, typically, you would not unless there's something really primitive, like a string or something like that. STEPHANIE: Okay, how does that work? JOËL: So you have some conversion layer that happens. STEPHANIE: Got it. JOËL: Honestly, I think that's my preference, and not just at the front end versus API layer but kind of all throughout. So the shape of an object in the database should not be the same shape as the object in the business logic that runs on the back end, which should not be the same shape as the object in transport, so JSON or whatever, which is also not the same shape as the object in your front-end code. Those might be similar, but each of these layers has different responsibilities, different things it's trying to optimize for. Your code should be built, in my opinion, in a way that allows all four of those layers to diverge in their interpretation of not only what maybe common entities are, so maybe a user looks slightly different at each of these layers, but maybe even what the entities are to start with. And that maybe in the database what, we don't have a full user, we've got a profile and an account, and those get merged somehow. And eventually, when it gets to the front end, all we care about is the concept of a user because that's what we need in that context. STEPHANIE: Yeah, that's really interesting because now it almost sounds like separate systems, which they kind of are, and then finding a way to make them work also as one bigger [laughs] system. I would love to ask, though, what that conversion looks like to you. Or, like, how have you implemented that? Or, like, what kind of pattern would you use for that? JOËL: So I'm going to give a shout-out to the article that I always give a shout-out to: Parse, Don't Validate. In general, yeah, you do a transformation, and potentially it can fail. Let's say I'm pulling data from a GraphQL API into an Elm app. Elm has some built-in libraries for doing those transformations and will tell you at compile time if you're incorrectly transforming the data that comes from the shape that we expect from the schema. But just because the schema comes in as, like, a flat object with certain fields or maybe it's a deeply nested chain of objects in GraphQL, it doesn't mean that it has to be that way in your Elm app. So that transformation step, you get to sort of make it whatever you want. So my general approach is, at each layer, forget what other people are sending you and just design the entities that you would like to. I've heard the term wish-driven development, which I really like. So just, you know, if you could have, like, to make your life easy, what would the entities look like? And then kind of work backwards from there to make that sort of perfect world a reality for you and make it play nicely with other systems. And, to me, that's true at every layer of the application. STEPHANIE: Interesting. So I'm also imagining that the transformation kind of has to happen both ways, right? Like, the server needs a way to transform data from the front end or some, you know, whatever, third party. But that's also true of the front end because what you're kind of saying is that these will be different. [laughs] JOËL: Right. And, in many ways, it has to be because JSON is a very limited format. But some of the fancier things that you might have access to either on the back end or on the front end might be challenging to represent natively in JSON. And a classic one would be what Elm calls a custom type. You know, they're also called tagged unions, discriminated unions, algebraic data types. These things go by a bajillion names, and it's confusing. But they're really kind of awkward and hard, almost impossible to represent in straight-up JSON because JSON is a very limited kind of transportation format. So you have to almost, like, have a rehydration step on one side and a kind of packing down step on the other when you're reading or writing from a JSON API. STEPHANIE: Have you ever heard of or played that Wikipedia game Getting to Philosophy? JOËL: I've done, I think, variations on it, the idea that you have a start and an end article, and then you have to either get through in the fewest amount of clicks, or it might be a timed thing, whoever can get to the target article first. Is that what you're referring to? STEPHANIE: Yeah. So, in this case, I'm thinking, how many clicks through Wikipedia to get to the Wiki article about philosophy? And that's how I'm thinking about how we end up getting to [laughs] talking about types and parsing, and graphs even [laughs] on the show. JOËL: It's all connected, almost as if it forms a graph of knowledge. STEPHANIE: Learning that's another common topic on the show. [laughs] I think it's great. It's a lot of interesting lenses to view, like, the same things and just digging further and further deeper into them to always, like, come away with a little more perspective. JOËL: So, in the vein of wish-driven development, if you're starting a brand-new front-end UI, what is your sort of dream approach for working with an API? STEPHANIE: Wish-driven development is very visceral to me because I often think about when I'm working with legacy code and what my wishes and dreams were for the, you know, the stack or the technology or whatever. But, at that point, I don't really have the power to change it. You know, it's like I have what I have. And that's different from being in the driver's seat of a greenfield application where you're not just wishing. You're just deciding for yourself. You get to choose. At the end of the day, though, I think, you know, you're likely starting from a simple application. And you haven't gotten to the point where you have, like, a lot of features that you have to figure out how to support and, like, complexity to manage. And, you know, you don't even know if you're going to get there. So I would probably start with REST. JOËL: So we started this episode from a very back-end perspective where we're talking about Rails, and routes, and controllers. And we kind of ended it talking from a very front-end perspective. We also contrasted kind of a more RESTful approach, versus GraphQL, versus more kind of old-school RPC-style routing. And now, I'm almost starting to wonder if there's some kind of correlation between whether someone primarily works from the back end and maybe likes, let's say, REST versus maybe somebody on the front end maybe preferring GraphQL. So I'd be happy for any of our listeners who have strong opinions preferring GraphQL, or REST, or something else; message us at hosts@bikeshed.fm and let us know. And, if you do, please let us know if you're primarily a front-end or a back-end developer because I think it would be really fun to see any connections there. STEPHANIE: Absolutely. On that note, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeee!!!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
Joël has a fascinating discovery! He learned a new nuance around working with dependency graphs. Stephanie just finished playing a 100-hour video game on Nintendo Switch: a Japanese role-playing game called Octopath Traveler II. On the work front, she is struggling with a lot of churn in acceptance criteria and ideas about how features should work. How do these get documented? What happens when they change? What happens when people lose this context over time? Strangler Fig Pattern (https://shopify.engineering/refactoring-legacy-code-strangler-fig-pattern) Octopath Traveler 2 (https://octopathtraveler2.square-enix-games.com/en-us/) Empowering other departments (https://www.bikeshed.fm/388) Transcript: JOËL: You're the one who controls the pacing here. STEPHANIE: Oh, I am. Okay, great. Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: So long-time Bike Shed listeners will know that I'm a huge fan of dependency graphs for modeling all sorts of problems and particularly when trying to figure out how to work in an iterative fashion where you can do a bunch of small chunks of work that are independent, that can be shipped one at a time without having your software be in a breaking state in all of these intermediate steps. And I recently made a really exciting discovery, or I learned a new nuance around working with dependency graphs. So the idea is that if you have a series of entities that have dependencies on each other, so maybe you're trying to build, let's say, some kind of object model or maybe a series of database tables that will reference each other, that kind of thing, if you draw a dependency graph where each bubble on your graph points to other bubbles that it depends on, that means that it can't be created without those other things already existing. Then, in order to create all of those entities for the first time, let's say they're database tables, you need to work your way from kind of the outside in. You start with any bubbles on your graph that have no arrows going out from them. That means they have no dependencies. They can be safely built on their own, and then you kind of work your way backwards up the arrows. And that's how I've sort of thought about working with dependency graphs for a long time. Recently, I've been doing some work that involves deleting entities in such a graph. So, again, let's say we're talking about database tables. What I came to realize is that deleting works in the opposite order. So, if you have a table that have other tables that depend on it, but it doesn't depend on anything, that's the first one you want to create. But it's also the last one you want to delete. So, when you're deleting, you want to start with the table that maybe has dependencies on other tables, but no other tables depend on it. It is going to be kind of like the root node of your dependency graph. So I guess the short guideline here is when you're creating, work from the bottom up or work from the leaves inward, and when you're deleting, work from the top-down or work from the root outward or roots because a graph can have multiple roots; it's not a tree. STEPHANIE: That is interesting. I'm wondering, did you have a mental model for managing deleting of dependencies prior? JOËL: No. I've always worked with creating new things. And I went into this task thinking that deleting would be just like creating and then was like, wait a minute, that doesn't work. And then, you know, a few cycles later, realized, oh, wait, deleting is the opposite of creating when you're navigating the graph. And, all of a sudden, I feel like I've got a much clearer mental model or just another way of thinking about how to work with something like this. STEPHANIE: Cool. That actually got me thinking about a case where you might have a circular dependency. Is that something you've considered yet? JOËL: Yes. So, when you have a dependency graph, and you've got a circular dependency, that's a big problem because...so, in the creating model, there is no leaf node, if you will, because they both reference each other. So that means that each of these entities cannot be created on its own, the entire cycle. And maybe you've got only two, but maybe your cycle is, you know, ten entities big. The entire cycle is going to be shipped as one massive change. So something that I often try to do is if I draw a dependency graph out and notice, wait a minute, I do have cyclical dependencies, the question then becomes, can I break that cycle to allow myself to work iteratively? Because otherwise, I know that there's a big chunk that can't be done iteratively. It just has to be done all at once. STEPHANIE: Yeah, that's really interesting because I've certainly been in that situation where I don't realize until it's too late, where I've started going down the path thinking that, you know, I could just remove this one thing, or make this one change, and then find myself suddenly, you know, coming to the realization, oh, this other thing is now going to have to change. And then, at that point, there's almost kind of like the sunken cost fallacy [laughs] a little bit where you're like, well, I'm already in it. So, why don't I keep going? But your strategy of trying to find a way to break that cyclica...that is two words combined. [laughs] I meant to say circular dependency [laughs] is the right way to avoid just having to do it all in one go. Have you had to break up a cycle like that before? JOËL: Yes. I do it on a semi-frequent basis. The fancy term here for what I'm looking for when I'm building out a dependency graph is a directed acyclic graph. That's a graph theory or a computer science term that you'll hear thrown around a lot, DAG. I often like to...when building out a series of tasks that might also form a graph because you don't just model entities in your system; you might model a series of tasks as a graph. If there's a cycle in the graph, typically, I can break that using something like the strangler fig pattern, which is a way to kind of have some intermediate steps that are non-breaking that then lead you to the refactor that you want. And I've used the strangler fig pattern for a long time, never realizing until later that, oh, what I'm actually doing is breaking cycles in my task dependency graph. STEPHANIE: Hmm. I'm curious if you have noticed how these cycles come to be because I almost imagine that they get introduced over time, where you maybe did start with a parent and then you, you know, had dependencies. But then, over time, somehow, that circular dependency gets introduced. And I'm wondering if part of figuring out how to break that cycle is determining how things were introduced, like, over time. JOËL: In my experience, this happens in a lot of different ways because I'm using dependency graphs like this to give myself a mental model for a lot of different kinds of things. So maybe I'm thinking in terms of database tables. And so those might get a circular dependency that gets added over time as the system grows. But I'm also using it sometimes to model maybe a series of tasks. So I take a large task, and I break it down into subtasks that are all connected to each other. And that doesn't tend to sort of evolve over time in the same way that a series of database tables do. So I think it's very context-dependent. But there are definitely situations where it will be like you said, something that kind of evolves over time. STEPHANIE: That makes sense. Well, I'm excited for you to get to deleting some potential code or database tables that are no longer in use. That sounds like a developer's dream [laughs] to clean up all that stuff. JOËL: It's interesting because it's...a move operation is effectively what's happening. So I'm recreating tables in another system, pointing the ActiveRecord to this new system, and then deleting the existing ones in the local database. So, in a sense, I'm kind of traveling up this dependency graph from the leaf nodes into the root and then back down from the root to the leaves as I'm creating and then deleting everything or creating in one system, and then going back and deleting in the other system. STEPHANIE: Got it. Okay, so not necessarily a net negative but, like you said, a move or just having to gradually replace to use a new system. JOËL: That's right. And we're trying not to do this as, you know, okay, we're going to take the system down and move 50 tables from one system to another. But instead, saying, like, you know, one at a time, we're going to move these things over. And it's going to be small, incremental change over the course of a couple of weeks. And they're all pretty safe to deploy, and we feel good about them. STEPHANIE: That's good. I'm glad you feel good. [laughs] We should all be able to feel good when we make changes like that. JOËL: It's going to make my Fridays just so much more low-key just, like, yeah, hit that deploy button. It's okay. So, Stephanie, what is new in your world? STEPHANIE: So this is not work-related at all. But I just finished playing a 100-hour video game on my Nintendo Switch. [laughs] I finished a Japanese role-playing game called Octopath Traveler II. And I have never really played a game like this before. I've not, you know, put in many, many hours into something that then had an end, like, a completion. So, at the end of this very long game that had a very, you know, compelling and engaging story and I was invested in all of these characters, and by the time the credits were rolling, I felt a little sad to be leaving this world that I have been in many evenings over the last couple of months. Yeah, I don't know, I'm feeling both a little sad because, you know like I said, I got really invested in this game, but now I'm also kind of glad to have some free time back in [laughs] my life because that has definitely been the primary, like, evening activity that I've been doing to relax. JOËL: It sounds like this game had a very, like, a particularly immersive world that really pulled you in. STEPHANIE: It did. It did. It has these eight, like, different characters that you follow, like, different chapters and all of their stories, and then they all kind of come together as well. And the world was huge in this game. There were so many little towns to explore. And I didn't realize I was a completionist type. But I found myself running around opening every chest, talking to every NPC, and making sure that I, you know, collected all of my items [chuckles] before moving on. I also finished all of the side quests, which is, I think, you know, how I managed to put in over 100 hours into it. But yeah, it was very immersive, and I really enjoyed it. I don't know if this will become a norm for me. I know there are some people who are, you know, JRPG diehards and play a lot of these kinds of games, but they're a real, like, time investment for sure. JOËL: Are there achievements for completing everything? STEPHANIE: Not that I can tell on the Switch. I do know that, like, on other systems, you can see your progress on having done all of the things there are to do. But I think it's actually kind of better for me to just play [laughs] to just, like, think that I've done it all but not really, like, have something that tells me whether or not I've done it because then I would feel a lot more neurotic, I think, about being able to let it go where I am now. [laughs] JOËL: Right. If we've got, like, an explicit checklist of things or a progress bar, then it feels like you got to get to all the things. STEPHANIE: Yeah, exactly. I think there are still, you know, a couple more things that I wrote down on my little checklist of tasks that I would want to do once I feel like I want to come back to the game. But for now, like I said, I watched the credits roll. I teared up a little bit, you know, thinking about and reminiscing on my adventure with these characters, and I'm ready to put it down for a bit. JOËL: Did I hear correctly that you made a checklist for this game of things you wanted to do? STEPHANIE: Yes, [laughs] I did. JOËL: That's amazing. I love that. STEPHANIE: Yeah, you know, there are just so many things almost kind of like work where I had to, like, break down some of my goals. I wanted to, like, hit a certain level. I wanted to, you know, make sure I defeat these bosses that would help me get to those levels. And yeah, I got very into it. It was definitely a big part of my life for a couple of months. I got it originally because I needed a game to play on my flight to Asia back when I went to Japan. And I'm like, oh, like, this looks, you know, fun and engaging, and it will distract me for my, you know, over 10-hour flight. Turns out it distracted me for many, many more hours over several months [laughs] since then. But I had a great time. So yeah, that's what's new for me. Again, it's something I'd never really done before. I will say though I am very behind on my reading goal as a result. [chuckles] JOËL: I feel like this is a classic developer thing to do is, like, use the tools that we're used to in our job and then apply them to other parts of our life. And now it's just like, okay, well, I made a Kanban board to track my progress in this video game. You know, or, in my case, I'm definitely guilty of having drawn a dependency graph for the crafting tree for some video game. So I feel you really strongly there. STEPHANIE: Yes, I'm nodding heavily in agreement. I think it just scratches the same kind of itch of, you know, achieving, like, little things and then achieving one big thing. JOËL: So, speaking of places that are nice to have checklists and, like, well-defined requirements, you and I were talking earlier, and you have recently found some frustration around having user stories be defined well on your current project. STEPHANIE: Yes. So I've been reflecting a little bit about my current project and noticing what I think I might call product smells; I'm not quite sure, just some things I'm seeing in our day-to-day workflow that is getting me thinking. And I'm curious to hear if you've experienced something similar. But I find myself being tasked with a ticket that is quite vague. And maybe this was written by a product owner, or maybe it was written by another developer. And it is not quite actionable yet, so I have to go through the process of figuring out what I'm really needing to do here. I think another thing that has been quite frustrating is, you know, maybe we do find out what we want to do. And, like, I'll go back into the ticket, write down the requirements that I gathered, and do the ticket. I'll ship whatever change was required, and then I'll hear back from someone in a meeting or either as a one-off request in Slack. And it'll be like, "Hey, like, actually, you know, we want this to be different." And maybe you previously said that "Oh, the value for something would be 30. But now we found out more information; it should be 20. And so could you, like, make that change?" And then I'm not really sure what the best way to document a change like that is because it, you know, maybe existed in the previous ticket, but now it has changed. And do I create a new ticket for this, or do I just go ahead and make the code change? Like, who would know this information that we're now carrying about 20 being the value for, let's say, like, days or not meaning something in the code that we're writing? And I guess I've just been really curious about how to make sure that this doesn't become the norm where a lot of these conversations are just happening, and, you know, the people who happen to be in them know that this change happened. But then later on, someone is asking questions about, like, hey, like, when did this change? Or I expected this to be 30. But is this, you know, behaving as expected? So that was [laughs] a bit of a nebulous way of describing just, like, this churn that I feel with being the executor of work. But then, like, a lot of these things changing above me or separate from me and figuring out how to manage that. JOËL: When you were describing this scenario where you've done the work, and then someone's like, "Oh, could we change this value from, like, 30 to 20?" I'm thinking in my mind of the sort of beam that a lot of our designers face where it's like, you know, they have a design. They work on it; they do it. And then show it to a client, and the client is like, "I love this design. But could we just shift this box over, like, one pixel?" Like, they're, like, tiny, tiny, little changes that are kind of requested for change after you've done, like, this big thing. And, oftentimes, those pile-up. It's like, you shift it one pixel. It's like, oh, actually, you know what? Why don't we do it two pixels? And then it's like never-ending cycles, sometimes of, like, minute little changes. STEPHANIE: Yeah. But the minute changes really add up into, I think, really different behavior than what you maybe had decided as a team originally. And in the process of changing and evolving, I don't really know where documentation fits in. I've been working on this project that had a pretty comprehensive product design doc, where they had decided upfront on, you know, how the application is going to behave in many different scenarios. But again, like, that has changed over time. And when I recently had to onboard someone new to this project, you know, we sent over this document, and we're like, yeah, you can, you know, feel free to peruse it. But it's actually quite outdated. And then, similarly, right now, since the features that I'm working on are going through QA, there's been a lot of back and forth about, I'm seeing this, but the doc said that Y is supposed to happen, and I'm not sure if that's a bug or not. And I or someone else has to respond with that context that we were holding in our head about when that change happened. JOËL: That's really interesting. And I think it varies a lot based off the size of the organization. In a smaller organization, you're probably doing a lot of the requirements gathering yourself. You're talking to all the stakeholders. You're probably doing the QA yourself, or you're walking somebody else through QA. Versus a large organization, there might be an entirely separate product team, and a separate QA team, and a separate dev team. And a danger that I've often seen is where all of these teams are just kind of tossing work over the fence. And all you're given is a, you know, a ticket of, like, execute on this. Basically, turn these specs into code. And then you do that, and then you toss it over the fence to the QA team. And they check does the code do these things? And there's so much context that can easily get lost from one step to another. That being said, I think a lot of devs find it frustrating to do some of the requirements gathering work. How do you feel in general about scoping out a ticket or doing follow-up conversations with the product team about, like, "Hey, your idea for the ticket is this. How do you feel about doing these things? Or what if we cut these things?" Are those conversations that you enjoy having? Is that a fun part of the developer role for you? Or do you kind of wish that, like, somebody else did all of that so that you could, like, go heads down just writing code? STEPHANIE: I think it depends. That's a great question. Actually, I have so many thoughts in response. So let me try to figure out where I want to go from here. But I think I used to not like it. I used to be stressed out by it, and sometimes I still am. But when I thought my role was purely executing, to receive a ticket that is a bit vague, you know, I might have been left feeling, like, stuck, like, not knowing where to go from there. But now that has changed a bit because I received some really helpful feedback from an old manager of mine who was kind of invested in my growth. And she really suggested learning to become more comfortable with ambiguity because that just becomes more and more your job, I think, as you progress in your career. And so now I at least know what information I need to go get and have, you know, strategies for doing so. And also knowing that it's my job, like, knowing that no one else might be doing it, and it might just be me so that I can therefore get this ticket done. Because, like you said, that problem of throwing the work over the fence to someone else, at some point, that doesn't work because everyone has too much on their plates. And you have to just decide to be the one to seek the information that you need. JOËL: I think one way that, as developers, we bring a lot of value is that we help to cut through a lot of that ambiguity. I think if we see our role as merely translating a requirements document into code, that's a very simplistic point of view of what a talented developer does. So, like you said, as we grow in our careers, we start dealing with less and less defined things. We often have to start defining the problems that we're given. And we have to have these conversations with other teams to figure out what exactly we want to do. And maybe better understand why is it that we want to do this thing. What is the purpose of it? How are we going to get there? And my favorite: Do we have to do all of these things to hit the minimum value of this goal? Can I split this into multiple tickets? I love breaking down work. If I can make the ticket smaller, I'm all about that. STEPHANIE: Yes. I'm well aware. It's interesting about what you said, though, is that, like, yes, that becomes, in some ways, our superpower. But, for me, where the pain comes in is when that's not part of the expectations, where I am maybe tasked with something that is not clear enough, and yet, the time that I need to find that clarity is not given the respect that it, I think, deserves to build a good product because the expectation is that I should already be making progress on this ticket and that it will be delivered soon. You know, in that situation, I wish I had been in the room earlier. I wish I had been part of the process for developing the product strategy, or even just, like, have come in earlier to be able to ask, you know, why are we building this? And, like, what are some of the limitations on the technical side that we have? Because often, I find that it is a little too...not necessarily too late, but it is quite down the road that we then have to have these conversations, and it doesn't feel good. JOËL: I think that's one of the powerful things that came out of the agile movement was the idea that you have these cross-functional teams, that you don't have a separate product team, a separate dev team, a separate QA team, a separate design team that are all these isolated islands. But instead, you say, okay, we have a cross-functional team that is working on this aspect of the product. And it will be some product people, some dev people, some designers kind of all working together and communicating with each other. I know, shocking concept. And even depending on the context, a big idea is that the client or the customer is a part of that team. So, when we at thoughtbot work with a client, especially when they are maybe a smaller client like a startup founder, we make sure that they feel like they are a part of the team. They are involved in various meetings where we decide things. They have input. You know, they're part of that feedback cycle that we build. But that can also be the case for a larger company where your internal stakeholders are kind of built-in to be sort of part of your team. STEPHANIE: I've seen so many different flavors of trying to do Agile [laughs] that it has lost a little bit of meaning for me these days. And maybe we've incorporated some aspects of it. But then that idea of the tight feedback loops and then a cross-functional team where everyone is communicating that part has gotten a little bit lost, at least on my project. And I imagine that this is common, and our listeners might be finding themselves in a similar situation where things are starting to feel a little more like handing off and a little more like waterfall. [laughs] I'm curious, though, if you found yourself being requested to make a change from what the original decision was, how would you go about documenting that or not documenting it? Where do you think the best place for that information about how this feature now is supposed to work where should that live? JOËL: Are you talking about where do we document that a decision was made to change the original requirements of a task? STEPHANIE: Yes. JOËL: In general, I think that should live on the ticket just because as long as the ticket is live, I think it's good to have all the context on that ticket for whoever's working on it to have access at a glance. Sometimes it's worth it to say, you know what? We don't want to just keep this ticket live for weeks or maybe months on end. Let's ship this ticket, and create a follow-up to make a change later, especially if it's a change that's less important where it's like, you know what? It would be nice to have if...but, again, like, scope creep is a real danger. And so, again, me with the aggressive breaking up of tickets, I love to say, "That's a great idea. It would make a great change, not part of this ticket." So oftentimes, those changes I will push them into another ticket. STEPHANIE: That's interesting. What about documentation beyond the current work? So I'm thinking about once, you know, a feature is delivered, how do people in the organization then know how this feature is supposed to work? Like moving forward as something that is customer-facing. JOËL: That can vary a lot by organization, I think because there's a couple of different aspects to this. You have maybe some internal-facing documentation; maybe some customer support people need to know about the way the interface has changed. And then you also have customer-facing documentation where maybe you want some sort of, you know, you want a blog post talking about the new feature or some kind of release notes or something like that to be shared with your customers. And compiling that might look very different than what you do for your internal service reps. STEPHANIE: Yeah, I like that. It's true that the customer documentation is really helpful. At least for, the product that I'm working on, it has very comprehensive documentation about how to use that for its customers. And that has been really helpful because, hopefully, that should be the truest [laughs] information out there. But sometimes, you know, I find myself in meetings where none of us really know what happens. For example, a question that was asked recently is our product has a free trial capability. But it was unclear what happens to all of the data that the customer is getting access to as a feature. Like, what happens to that data after the free trial ends? Like, if they then have purchased a license, do they still have access to their free trial data? If, you know, there's a lapse between then, does it just get deleted, or will it show up again? And no one really knew the answer to that. And I think that was another area that got my spidey senses tingling a little bit; I think because it reminded me of...there was a definition I read somewhere of legacy code that is basically when the person who has the most context about how a piece of code works and then they leave the company and that institutional knowledge no longer exists, like, that is legacy code. And I almost think that that also applies to product a little bit where a legacy product is something where no one quite knows what is supposed to happen, but it's still being used by users. JOËL: That's a really fun definition there. I think there's sort of two related questions that are slightly different here, which is, one, how does the code behave? So, what happens when someone's trial period expires? And it's quite possible that no one on the team knows what actually happens when that time expires. And then the second question is, what should happen when a trial expires? And it's possible, again, that the product team didn't think through any of the edge cases. They only went for the happy path. And so it's possible if that is also fully undefined and no one knows. STEPHANIE: Yeah, I like that distinction you made a lot because they definitely go hand in hand, where someone realizes that some weird edge case happened, and then suddenly, they're asking those questions. And, you know, we realized, like, oh, like, that just didn't have enough, like, intention or thought behind how it was coded. So, like, it really is; who knows, right? Just whatever seems to happen. And I think that this actually kind of reminds me of a previous episode we did about empowering other departments in the company because, ultimately, a lot of those questions about, like, how does this work? What happens? Ends up going to a developer who has to go and read the code and report back. And while, you know, we do have that power, it can also be a bit of a curse, I think. [laughs] JOËL: I think this is an area where, as developers, we're maybe particularly skilled. Because of the work that we do, our brains are kind of wired to think about all of the edge cases, and sometimes they can be really annoying. But I think there's a lot of value sometimes when maybe the product team comes to us with a maybe somewhat nebulously scoped ticket or a series of tickets for, let's say, a free trial period feature that only goes through the happy path. And then sometimes it's up to us to push back or to follow up and say, "Okay, great. We've got a bunch of tickets for a free trial period. Have you thought about what happens after a trial expires but the person hasn't converted to a paying customer?" And then, oftentimes, the answer is like, "Oh, no, we didn't think about that." And I think oftentimes, as developers, our job is to kind of, like, seek out a lot of those edge cases. And we have a lot of techniques and methodologies that we use to try to find edge cases, things like test-driven development, various modeling tools that we'll try to use to make sure that we don't just crash or do something bad in our code. But what should the actual behavior be? That's a conversation that we need to have. And hopefully, that's one that maybe the product team has already had on their own. But oftentimes, the benefit of having that cross-functional team is the ability to kind of have that back and forth and say, "Hey, what about this edge case? Have we thought about that? How do we want that to behave?" STEPHANIE: Yeah, that actually made me think about the idea of tech debt but almost at a product level, where, hey, it turns out that we have all of these things that we didn't quite think through, and it's now causing problems. But how much do we invest in revisiting it? Because, you know, maybe this feature is several years old, and it was working just okay enough for it to, you know, be valuable. But we're now discovering these things and, you know, like, do we invest in them? Or are we more focused on, you know, coming up with new things and new features for our customers? JOËL: That's a classic prioritization problem. It also kind of reminds me of the idea of an MVP. What are the actual, like, minimum set of features that you need in order to try out something or to ship something to customers? And, you know, maybe we don't need some special behavior if your trial account doesn't convert. Maybe we're okay [laughs] that you log in, and the app just crashes. Probably not, because we would probably want you to convert to a paying customer at some point. But maybe we're okay if you just get a screen that says, "You have no projects," when, in fact, you did have projects. It's just that you're no longer on the free trial. Again, for business reasons, probably we want a call to action there that says, "You have five projects. They are not available to you. Please pay to unlock your projects again." That probably converts better. But, again, now that is a business decision. And that becomes a prioritization question that the team as a whole gets to address. Sometimes it can also be some really fun prioritization things where if you're on a really tight schedule, you might ship some features live knowing that you have a time limit, but you don't have to necessarily ship other things. So let's say you've got a 30-day trial, and maybe you ship that before you've even implemented what the dashboard will look like after your free trial has expired, and that's fine because no one's going to hit that condition for 30 days. So now you've got 30 days to go out and handle that condition. And maybe that's okay because it allowed you to get to market a little bit faster, allowed you to cut scope, break those tickets, yes, and just move that much faster. But it does require discipline because now you're on the clock. You've got 30 days to fix that edge case or potentially face some unhappy customers. STEPHANIE: Yeah, I think that's quite a funny way to handle it. It's really ruthless prioritization [laughs] there. But what you said was very interesting to me because I was thinking about how there is such a focus on new feature development and that being the thing that will attract customers or generate more money. But there is something to be said about investigating some of our old features of our existing system and finding opportunities there. And oftentimes, revisiting them will reduce the amount of pain [chuckles] that, you know, developers feel having to kind of keep track or have an eye on, like, where things are airing out, but then don't have the time to really invest in making it better or making that part of the product better. JOËL: I think that's a great opportunity then to have a conversation with other parts of the team. Typically, I think you have to convert some of those into more of a business case. So the business people in the company or the product people might not care about the sort of raw metrics that you see as a developer. Oh, we got an exception with a stack trace in this part of our app. What does that even mean? But if you say, hey, people who signed up for a free trial and then didn't immediately convert within 30 days who want to come back a month later and convert are unable to do so. And we've seen that that's about 10% of the people who signed up for a free trial. Well, now that's an interesting business question. Are we losing out on potentially 10% of customer acquisition? I'll bet the sales and marketing people care a lot about that. I'll bet the business people care a lot about that. The product people probably care a lot about that. And now we can have a conversation about should we prioritize this thing? Are these metrics that we should improve? Is this a part of our code that's worth investing in? STEPHANIE: Yeah, I like that because, in some ways, asking those questions about how does it work? Like, that is really an opportunity because then you can find out, and then you can make decisions about whether it's currently providing enough value as is or if there is something hiding under there to leverage. JOËL: And I think that's one of the other places where, as developers, we provide value to clients is that we can sort of talk both languages. We can talk product language. We can talk business language. But we can also talk code. And so when we see things like that in code, sort of translate that into, like, what are the business impacts of this code change? Which then allows everyone to make the best possible decisions for the mission of the organization that you're a part of. So we've talked about a variety of sort of patterns and anti-patterns that surround working through some of this churn on a product. I'm curious, Stephanie, for you, what's maybe one concrete thing that you've done recently that you've found has really helped you navigate this and maybe help reduce some of the stress that you feel as you navigate through this? STEPHANIE: Yeah, I think, for me, one of the worst things is when that discussion is had in a meeting or a [inaudible 35:45] and then is not put anywhere. And so, one thing I've been making sure to do is either asking the person who made the request to write it down, either on the ticket or in Slack. Or I will write it down, you know, I will document the outcomes of what we talked about and putting it in a public space so that people are aware. I think that small action has been helpful because we hold so much of this in our heads. And I've been finding that it ends up being hard for people to rotate onto different projects and, you know, get onboarded and up to speed effectively because there's so much knowledge and context transfer happening. But even just putting it in a place where maybe it's not relevant to everyone, but at least they see it. And then the next time that they're asked or maybe, like, do come around to working on this, they, like, have some fragment of a memory that they saw something about this. So that has been really helpful. It actually dovetails really nicely into what we were talking about with opportunities, too, because once it's out there, like, maybe someone else will see it and have an idea about how it could be better or that change not being what they expected, and they can weigh in a little more. So that's what I'm trying to do. And I think it's also nice to see how often that happens, right? If we're constantly seeing things changing because we have a written record of it, that could be helpful in bringing up and investigating further as to, like, why is this happening? Like, why do we experience this churn? And is that something we want to address? JOËL: Yeah, because an element that we haven't talked at all about is any sort of feedback cycle or retrospective, where we can talk about these things and having that written trail and saying, "Oh, we changed this decision five times in the past week, like, really churned there." Now maybe that prioritizes it to be an important thing to talk about and to improve for the next cycle. STEPHANIE: What I feel really strongly about is when, you know, each individual on a team is feeling this pain, but it not being known that it's actually a collective issue. Because maybe these things are happening in one-on-one conversations, and we don't realize that, like, oh, maybe there is something bigger here that we could improve on. And so the more eyes on it there are, the more visible it is, I think, that the easier it is to address. JOËL: I love that, the power of writing things down. On that note, shall we wrap up? STEPHANIE: Let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeee!!!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
Joël's new work project involves tricky date formats. Stephanie has been working with former Bike Shed host Steph Viccari and loved her peer review feedback. The concept of truthiness is tough to grasp sometimes, and JavaScript and Ruby differ in their implementation of truthiness. Is this a problem? Do you prefer one model over the other? What can we learn about these design decisions? How can we avoid common pitfalls? [EDI](https://www.stedi.com/blog/date-and-time-in-edi](https:/www.stedi.com/blog/date-and-time-in-edi) [Booleans don't exist in Ruby](https://thoughtbot.com/blog/what-is-a-boolean](https://thoughtbot.com/blog/what-is-a-boolean) [Rails valid? method](https://api.rubyonrails.org/classes/ActiveRecord/Validations.html#method-i-valid-3F](https://api.rubyonrails.org/classes/ActiveRecord/Validations.html#method-i-valid-3F) Parse, don't validate (https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/) Javascript falsiness rules (https://www.sitepoint.com/javascript-truthy-falsy/) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a little bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: So I'm on a new project at work. And I'm doing some really interesting work where I'm connecting to a remote database third-party system directly and pulling data from that database into our system, so not via some kind of API. And one thing that's been really kind of tricky to work with are the date formats on this third-party database. STEPHANIE: Is the date being stored in an unexpected format or something like that? JOËL: Yes. So there's a few things that are weird with it. So this is a value that represents a point in time, and it's not stored as a date-time value. Instead, it's stored separately as a date column and a time column. So a little bit of weirdness there. We can work with it, except that the time column isn't actually a time value. It is an integer. STEPHANIE: Oh no. JOËL: Yeah. And if you're thinking, oh, okay, an integer, it's going to be milliseconds since midnight or something like that, which is basically how Postgres' time of day works under the hood, nope, that's not how it works. It's a positional digit thing. So, if you've got the number, you know, 1040, that means 10:40 a.m. STEPHANIE: Oh my gosh. Is this in military time or something like that, at least? JOËL: Yes, it is military time. But it does allow for all these, like, weird invalid values to creep in. Because, in theory, you should never go beyond 2359. But even within the hours that are allowed, let's say, between 1000 and 1100, so between 10:00 and 11:00 a.m., a clock only goes up to 59 minutes. But our base 10 number system goes up to 99, so it's possible to have 1099, which is just an invalid time. STEPHANIE: Right. And I imagine this isn't validated or anything like that. So it is possible to store some impossible time value in this database. JOËL: I don't know for sure if the data is validated or not, but I'm not going to trust that it is. So I have to validate it on my end. STEPHANIE: That's fair. One thing that is striking me is what time is zero? JOËL: So zero in military time or just 24-hour clocks in general is midnight. So 0000, 4 zeros, is midnight. What gets interesting, though, is that because it's an integer, if you put the number, you know, 0001 into the database, it's just going to store it as 1. So I can't even say, oh, the first two digits are the hours, and the second two digits are the minutes. And I'm actually dealing with, I think, seconds and then some fractional part of seconds afterwards. But I can't say that because the number of digits I have is going to be inconsistent. So, first, I need to zero pad. Well, I have to, like, turn it into a string, zero pad the numbers so it's eight characters long. And then, start slicing out pairs of numbers, converting them back into integers, validating them within a range of either 0 to 23 or 0 to 59, and then reconstructing a time object out of that. STEPHANIE: That sounds quite painful. JOËL: It's a journey for sure. STEPHANIE: Do you have any idea why this is the case or why it was created like this originally? JOËL: I'm not sure. I have a couple of theories. I've seen this kind of thing happen before. And I think it's a common way for developers who maybe haven't put a lot of thought into how time works to just sort of think, oh, the human representation. I need something to go in the database. On my digital clock, I have four digits, so why not put four digits in the database? Simple enough. And then don't always realize that there's all these edge cases to think about and that human representations aren't always the best way to store data. STEPHANIE: I like how you just said that that, you know, we as humans have developed systems that are not quite, you know, the same as how a computer would. But what was interesting to me...something you said earlier about time being a fixed point. And that is different from time being a value, right? And so here in this situation, it sounds like we're storing time as a value, but really, it's more of the idea of, like, a point. JOËL: Interesting. What is the difference for you between a point and a value? STEPHANIE: I suppose a value to me...And I think we talked about this a little bit on a previous episode about value objects and also how we stored numbers, like phone numbers and credit card numbers and stuff like that. But a value, like, I might want to do math on. But I don't really want to do math on time. Or, specifically, if I have this idea of a specific point in time, like, that is fixed and not something that I could mutate and expect it to be the same thing that I was trying to express the first time around. JOËL: Oh, that's interesting because I think when it comes to time and specifically points in time, I sometimes do want to do math on them. And so, specifically, I might want to say, what is the time that has elapsed between two points in time? Maybe I have a start time and an end time, and I want to say how much distance is there between the two? If you use this time system where you're storing it as an integer number where the digits have positional values, because there's all those gaps between, you know, 59 and 99 that are not valid, math breaks down. You've broken math by storing it that way. So you can't get an accurate difference by doing math on that, as opposed to if you store it as a counter, which is what databases do under the hood, but you could do manually. If you just wanted to use an integer column, then you can do math because it's just a number of seconds since the beginning of the day. And you can subtract those from each other. And now you have these number of seconds between the two of them. And if you want them in minutes or hours, you divide by six here, 3600, and you get the correct response. STEPHANIE: Yeah, that is really interesting because [chuckles] in this situation, you have the worst of both worlds, it seems like. [laughs] JOËL: The one potential benefit is, I think, it's maybe more human-readable. Although, at that point, I would say if you're not doing math on it and you want something human-readable, you probably don't want an integer. You probably want a string. And maybe you even store it as, like, ISO 8601 time string in the database, or even just hour:minute:second split by a colon or whatever it is but just as a string. Now it's human-readable. You can still sort by it if you go from largest to smallest increment in your format. You can't do math, but then you weren't doing math on it anyway. So that's probably a nice compromise solution. But, ideally, you'd use a native, you know, time of day column or a date-time or something like that. STEPHANIE: For sure. Well, it sounds like something fun to contend with. [laughs] JOËL: One thing that was brought to my attention that I'd never heard about before is that potentially a reason it's stored that way is because of an old data format called EDI—I think it's Electronic Data Interchange—that dates from ages ago, you know, the '60s or '70s, something like that. Before, we had a lot of standards for data; this is how...an emerging standard that came for moving data between systems. And it has a lot of, like, weird things with the way it's set up. But if you're dealing with any sort of older data warehouses or older business systems, they will often exchange. And sometimes, you're going to store data in something that approximates this older EDI format. And, apparently, it has some weirdness around dates where it kind of does something like this. So someone was suggesting, oh, well, if you're interacting with maybe an older, you know, a lot of, like, e-commerce platforms or banking systems, probably airline systems, the kind of things you'd expect to be written in, let's say, COBOL... STEPHANIE: [laughs] JOËL: Have a system that's kind of like this. So maybe that wouldn't be quite as surprising. STEPHANIE: Yeah, that is really interesting. It just sounds like sometimes you're limited by the technology that you're interacting with. And I guess the one plus side is that, in your system, you can make the EDI work for you, hopefully. [laughs] Whereas perhaps if you are talking to some of those older technologies that don't know how else to convert date types and things like that, like, you just kind of have to work with what's available to you. JOËL: Yeah. And that's got me realizing that a lot of these older, archaic systems are still online and very much a part of our software ecosystem and that there's a lot of value in learning some software history so that I'm able to recognize them and sort of work constructively with them when I have to interact with that kind of system. STEPHANIE: Yeah, I really like that mindset. JOËL: So, Stephanie, what's new in your world? STEPHANIE: So, last week, we talked about writing reviews for ourselves and our peers. And one thing that happened in between the last episode and this one is Steph Viccari, former co-host of this podcast, who I've been working with really closely on this project of mine; she was writing a peer review for me. And one thing that she did that I really loved was she sent me a message and asked me a few questions about the direction of the review that I was wanting and what kind of feedback would be helpful for me. And some of the things she asked were, you know, "Is there a skill that you're actively working on? Is there a skill you'd like to start working on?" And, like, what my goals are for the feedback. Like, how can she tailor this feedback to things that would help my progression and what I hope to achieve? And then my favorite question that she asked was, "What else should I know but didn't think to ask?" And I thought that was a really cool way of approaching. You know, she's coming to this, like, wanting to be helpful, but then even still, like, there are things that she knows that I am kind of the expert on in my own career progression, and I really liked that. I think I'd mentioned last week that part of the feedback you want to be giving is, you know, something that will be helpful for that person, and centering them in it, instead of you is just a really awesome way to do that. So I was very appreciative that she asked me those questions. JOËL: That's incredibly thoughtful. I really appreciate that she sent that out to you. What did you respond for the is there something else I should know but didn't know to ask? STEPHANIE: Yeah. I mentioned that more and more, I'm realizing that I am not interested in management. And so what would be really helpful for me was to ground most of the feedback in terms of my, like, technical contributions. And also, that one thing that I'm thinking about a lot is how to be an individual contributor and still have an impact on team health and culture because that is something I care about. And so I wanted to share that with her because if there are things that she can identify in those aspects, that would be really awesome for me. And that can kind of help guide her away from a path that I'm not interested in. JOËL: I think having that kind of self-awareness is really powerful for yourself. But then, when you can leverage that to get better reviews that will help you get even further down the path that you're hoping to go, and, wow, isn't that just, like, a virtuous cycle right there that's just building on itself? STEPHANIE: Yeah, for sure. I think the other thing I wanted to share about what's new in my world that has been just a real boost to my mood is how long the days are right now because it's summer in North America. And yesterday was the summer solstice, and so we had the longest day of the year. The sun didn't set until 8:30 p.m. And I just took the opportunity to be outside. I took a swim in the lake, which was my first swim of the season, which was really special. And my friend had just a nice, little, like, backyard campfire hang out. And we got to roast some marshmallows and just be outside till the sunset. And that was really nice. JOËL: When you say the lake, is that Lake Michigan? STEPHANIE: Yes, I do mean Lake Michigan. [laughs] I forget that some people just don't have a giant lake next to them [laughs] that they refer to as the lake. JOËL: It's practically an inland sea. STEPHANIE: Yes, you can't see the other side of it. So, to me, it kind of feels like an ocean. And yesterday, when I was in the water, I also was thinking that I felt like I was just in a giant bathtub. [chuckles] JOËL: So I'm in New England, and most of the bodies of water here are not called lakes. They're called ponds. STEPHANIE: Really? JOËL: No matter the size. STEPHANIE: Oh. JOËL: I guess lakes is reserved for things like what you have that are absolutely massive, and everything else is a pond. STEPHANIE: That's so funny because I think of ponds as much smaller in scale, like a quaint, little pond. But that's a really fun piece of regional vocabulary. So one interesting thing happened on my client project this week that I wanted to get your input on because I've definitely seen this problem before, and still, it continues to crop up. But I was working on a background job that we were passing a Boolean value into as one of the parameters that we would then, you know, use down the line in determining some logic. And we, you know, made this change, and then we were surprised to find out that it continued to not work the way we expected. So we got some bug reports that we weren't getting into one of the branches of the conditional based on that Boolean value that we were passing in. And we learned, after a little bit of digging, that it turns out that those values are serialized because this job is actually saved in -- JOËL: Oh no. STEPHANIE: [chuckles] Yeah. It inherits from the ActiveRecord, actually, and is saved in our database. And so, in that process, the Boolean value got serialized into a string and then did not get converted [chuckles] back into a Boolean. And so when we do that if variable check, it was always evaluating to true because strings are truthy in Ruby. JOËL: Right. The string false is still truthy. STEPHANIE: A string false is still truthy. And we ended up having to coerce it into a Boolean value to fix our little bug. But it was just one of those things that was really frustrating, you know when you feel really confident that you know what you're doing. You're just writing a conditional statement. And it turns out the language beguiled you. [laughs] JOËL: I've run into similar bugs when I'm reading from environment variables because environment variables are always strings. But it's common that you'll be setting some kind of flag. So when you're setting the environment variable, you're setting something to true or false. But then, when you're reading it, you have to explicitly check if this environment variable double equals the string true, then do the thing. Because if you just check for the value, it will never be false. STEPHANIE: Right. And I kind of hate seeing code like that. I don't know; something about it just rubs me the wrong way because it just seems so strange, I suppose. JOËL: Is it just, like, those edge cases where you specifically have to do some kind of, like, double equals check on a value that feels like it should be a Boolean? Or do you kind of feel a bit weird about the concept of truthiness in general? STEPHANIE: I think the concept of truthiness is very hard to grasp sometimes. And, you know, when you're talking about that edge case where we are setting...we're checking if the string is the string true. That means that everything else is false, right? So, in some ways, I think it's just really confusing because we've expanded the definition of what true and false mean to be anything. JOËL: That's really interesting because now you have to pick. Are you checking against the string true, or are you negatively checking against the string false? And those are not equivalent because, like you said, now you're excluding every other string. So, is the string "Hello, World" put you in the false branch or the true branch? STEPHANIE: Who's to say? [laughs] I think a similar conundrum also occurs when we use predicate matchers in our tests. I think this is a gripe that I've talked about a little bit with others when we're writing tests and especially if we're writing a predicate method, and then that's what we're testing, right? We kind of are expecting a true or false value. And when our test expects something to be truthy rather than explicitly saying that we expect the return value to be true, that is sometimes a bit confusing to me as well because someone could theoretically change this method and just have it return "Hello, World," like you said, as a string, like, anything else. And that would still pass the test. JOËL: And it might even pass your code in most places. STEPHANIE: Right. And I suppose that's okay. Is it okay? I don't know. I'm not sure where I land on this. JOËL: I used to be a kind of hardcore Boolean person. STEPHANIE: [laughs] That's a sentence no one has ever [laughs] said. JOËL: I like my explicit trues and falses. I don't like the ambiguity of saying, like, oh, if person do a thing, it's, like, oh, what is person here? Is this a nil check? Is it explicitly false? Do you just want to know that this person is non-empty? Well, what exactly are you checking? So I like the explicitness of saying, oh, if person dot present, or if person dot empty, or if person dot nil. And I think maybe spending some time in some more strongly typed languages has also kind of pushed me a little bit in that direction, where it's nice to have something that is explicitly either just true or just false. And then you completely eliminate that problem of, like, oh, but what if it's neither true nor false, then what do we do for that branch there? And the answer is your compiler will reject that program or say, "You've written a bad program." And you never reach that point where there's a bug. I've slowly been softening my stance. A fellow thoughtbot colleague has written an article why there is no such thing as a Boolean in Ruby. Everything is just shades of gray and truthiness and falsiness. But from the perspective of a program, there is no such thing as a Boolean. And that really opened my eyes to a different perspective. I don't know that I fully agree, but I'm kind of begrudgingly acknowledging that Mike makes a good point. STEPHANIE: Yes, I read the blog post that he wrote about this exact problem. And I think it's called "Booleans Don't Exist in Ruby." And I think I similarly, like, came away with, like, yeah, I think I get it if I just suspend my disbelief, you know, hard enough. [laughs] But what you were saying about, like, liking the explicitness, right? And liking the lack of ambiguity, right? Because when you start to believe that Booleans don't exist, I think that really messes with your [laughs] head a little bit. And one takeaway that I got from that blog post, kind of like we mentioned earlier, is that there is such thing as false, and then everything else is true. And I guess that's kind of how Ruby operates. JOËL: Sort of, because then you have the problem of nil, which is also falsy. STEPHANIE: That's true, but nil is nothing. [laughs] JOËL: That's one of the classic problems as well when you're trying to do a nil check, or maybe some memoization, or maybe even, say, cache this value, or store this value, or initialize this value if it's not set. And assuming that doing nil is falsy, so you'll do some kind of, like, or equals, or just some kind of expression with an or in it thinking, oh, do this extra work if it's nil because then it will trigger the branch. But that all breaks down if potential for your value to be false because false and nil get treated the same in conditional code. STEPHANIE: Right. I think this could be a whole separate conversation about nil and the idea of nothingness. But I do think that, as Ruby developers, at least in the Ruby world, based on what I've seen, is that we lean on nil in ways that we maybe shouldn't. And we end up having to be very defensive about this idea of nil being falsy. But that's because we aren't necessarily thinking as hard about our return values and what our arguments are that; it ends up causing problems in evaluating truthiness when we're having to check those objects that could be nil. JOËL: In terms of the way we communicate with the readers of our code, and, as a reader, I generally assume that a Ruby method that ends with a question mark will return a true Boolean, either true or false. Is that generally your expectation as well? STEPHANIE: I want to say yes, but I've clearly experienced enough times where that's not the case that, you know, it's like, my ideal world and then reality [laughs] and having to figure out how to hold both of those things. JOËL: It's one of those things that's mostly true. STEPHANIE: I want to believe it because predicate methods and, like, the Ruby Standard Library mostly return Boolean values, at least to my knowledge. And if we all kind of followed that [laughs] pattern, then it would be clear. But I think there's a part of me that these days mostly believes it to be true that I will be getting a Boolean value (And, wow, even as I say this, I realize how confusing [laughs] this is starting to sound.) and that until I'm not, right? Until I'm surprised at some point. JOËL: I think there's two things I expect of predicate methods in Ruby. One is that they will return, like, a hard Boolean, either true or false. The second is that they are purely query methods; they don't do side effects. Neither of those are consistent across the ecosystem. And a classic example of violating that second guideline I have in my mind is the valid question mark method from Rails. And this really surprised me the first time I tripped into this because when you call that on an object, it doesn't just tell you whether or not the object is valid. It actually mutates the underlying object by populating the error messages' hash. So if you have an invalid object and you examine its error messages' hash, it will be empty until you call the valid question mark method. So sometimes, you don't even care about the return value. You're just calling valid to mutate the object so that you can access the underlying hash, which is that's weird code when you call a predicate method but then totally ignore the output. STEPHANIE: Yeah, that is strange because I have definitely seen it where we are calling the valid method to validate, and then we end up using the error messages that are set on that object later. I think that's tough because, in some ways, you do care about whether the object is valid or not. But then also, the error messages are helpful usually and when you're trying to use that method. The point is to validate it so that you can hopefully, like, tell the user or, like, the consumer of your system, like, what's wrong in validation. But it is almost, like, two separate things. JOËL: It is. And sometimes, it's really hard to split those two apart. So I'm not throwing shade at the Rails dev team here. Some of these design decisions are legitimately difficult to make. And what's most useful for the most people the most time is often a compromise. I think you brought up the idea of separating those two things. And I think there's a general principle here called command-query separation. That's, like, the fancy way of talking about what you were saying. STEPHANIE: One thing that I was just thinking about kind of when we initially picked off this conversation was the idea of how things outside the Ruby ecosystem or the Ruby world interact with what we're returning in terms of Boolean values. And so when I mentioned the object being serialized because of, you know, our database and, like, background job system, that's an entity that's figuring out what to do with the things that we are returning from Ruby. And similarly, when you're talking about environment variables, it's like, our computer system talking to now our language and those things being a bit different. Because when we, like, suspend our disbelief about what is truthy or falsy in Ruby, at least we're doing it in, like, the world of Ruby. And as soon as we have to interact with something else, like, maybe that's when things can get a little hairy because there's different ideas about truthiness there. And so I'm kind of also thinking about what we return in APIs and maybe, like, that being an area where some explicitness is more required. JOËL: Whenever I'm consuming third-party data, I'm a big fan of having some kind of transformation or parse step. This is inspired in part by the "Parse, Don't Validate" article, which I'll link in the show notes. So, if I'm reading data from a third-party API and I want it to be a Boolean, then maybe I should do the transformation myself. So maybe I check literally, is it the string true or the string false, and anything else gets rejected? Maybe I have...and maybe I'm a little bit more permissive, where I also accept capital T or capital F, and I have, like, some rules for transforming that. But the important thing is I have an explicit conversion step and reject any bad output. And so for something like an environment variable, maybe that would look like looking for true or false and raising if anything else is there. So that we try to boot the app, and it immediately crashes because, hey, we've got some, like, undefined, like, bad configuration that we're trying to load the app with. Don't even try to keep running. Hard crash immediately. Fix it, and then come back. STEPHANIE: Yeah, I like that a lot because the way we ended up fixing this issue with the background job that I mentioned was just coercing our string value into a Ruby Boolean in the job that we were then, like, running the conditional in. But really, what we should have done is have fixed that at a higher level and where we parse and deserialize, like, the values we're getting from the job to prevent this kind of in the future because right now, someone can do this again, and that's a real bummer. JOËL: I always love those deeper conversations that happen after you've had a bug that are like, how do we prevent this from happening again? Because sometimes that's where you have the deepest learnings or the most interesting insights or, you know, ideas for Bike Shed episodes. I'm really curious to contrast JavaScript's approach to truthiness to Ruby's because even though they both use the same idea, they kind of go about it differently. STEPHANIE: Tell me more. JOËL: So, in Ruby, an empty array and an empty string are truthy. JavaScript decided that empty things are falsy. And I forget...there's a whole table that shows the things that are truthy and falsy in JavaScript. I want to say zero is falsy in JavaScript but don't quote me on that, which can also lead to some interesting edge cases you have to think about. STEPHANIE: Okay, yes. This is coming back to me now. I think depending on what, you know, ecosystem or language or world I'm in, I have to just only be able to think about what is true in this world [laughs] and then do that context switching when I am working in something else. But yeah, that is a really interesting idea. Someone decided [laughs] that this was their idea of true or false. JOËL: I'm curious if you have a preference for sort of JavaScript's approach to falsiness where a lot more types of values are falsy versus Ruby, which said pretty much only nil and false are falsy. Everything else is truthy. STEPHANIE: Hmm, that is an interesting question. JOËL: Because in Ruby then or, I guess, in Rails, we end up with the present predicate method that is specifically checking for not only nil and false but also for empty array, empty string, those kinds of things. So, if you find yourself writing a lot of present matchers in your code, you're kind of leaning on something that's closer to JavaScript's definition of falsiness than Ruby's. But maybe you're making it more explicit. STEPHANIE: Right. In JavaScript, I see a lot of double bangs in lieu of those predicate methods. But I suppose by nature of having to write those predicate methods in Ruby, we're, like, really wanting something else, I think. And maybe...I guess it is just a question of explicitness like you're saying, and which I prefer. Is it that I need to be explicit to convey the idea that I want, or is it nice that the language has just been encoded that way for me? JOËL: Or maybe when you write conditionals, if you find yourself doing a lot of presence checks, do you find that you typically are trying to branch on if not null, not false, not empty more frequently than just if not null, not false? Because that's kind of the difference between Ruby's model and JavaScript's model. STEPHANIE: Hmm, the way you posed that question is interesting because it makes me think that sometimes it's quite defensive because we have to check for all these possible return values. We are unsure of what we are getting back. And so this is kind of, like, a catch-all for things that we aren't really sure about. JOËL: Yeah, I mean, that's the fun of dynamic programming languages. You never know exactly what you're going to get as long as things respond to certain methods. You really lean into the duck typing. And I think that's Mike's argument in his article that "Booleans Don't Exist" in that as long as something is responding to methods that you care about, it doesn't matter if you're dealing with a true Boolean or some kind of other value. STEPHANIE: Right. So I suppose the ideas of truthiness then are a little bit more dependent on how people are using the language though it seems like a chicken-and-egg situation to me. [laughs] JOËL: It is really interesting to me in terms of maybe thinking about use cases in my own code if I'm having to...if I'm writing code that leans on truthiness where I can say just, you know if user. But then knowing that, oh, that doesn't account for, like, an empty value. Do I then also need to add an extra check for emptiness? And maybe if I'm in a Rails project, I would reach for that present matcher where I wouldn't have to do that in JavaScript because I can just say, if user, and that already automatically checks for presence. So I'm kind of wondering now in my mind, like, which default would fit my use cases more? Or, if I go back to an older version of myself, I will say I don't want any of these defaults. They're all too ambiguous. I'm going to put explicitly if user dot nil question mark, if that's the thing that I'm checking for, or if user dot empty question mark because I want my reader to know what condition I'm checking. STEPHANIE: Yeah, that is interesting, this idea of, like, which mode do you find yourself needing to use more and if that is accommodated for you because that's just the more common, like, use case or problem. I think that's something that I will be thinking about the next time I write a conditional [laughs] because, like I was saying earlier, I think I end up just leaning on what someone else has decided for me in terms of truthiness and not so much how I would like it to work for me. JOËL: And sometimes we don't want to fight the language too much, you know if I'm writing Elm, that everything is hard Booleans. And I know I'm never going to get a nil in a place where I'd expect true or false because the compiler would prevent that from happening. I know that I'm not going to get an empty value, potentially. There's ways you can do things with a type system where you can explicitly say no empty values are even allowed at this point. And if you do allow them, then the type system will say, "Hey, you forgot to check for the empty case. Bad program. I'm rejecting that." And then you have to write that explicit branch for, oh, if empty versus if present. So I really appreciate that style of programming. But then, when you're in a language like Ruby where you're not dealing with explicit types on purpose, how do you shift that mindset so that you don't need to know the type of the value that you're dealing with? You only want to say, hey, in this context, here's the minimal interface that I want it to conform to. And maybe it's just the truthy or falsiness interface, and everything beyond that is not relevant. STEPHANIE: I think it's kind of wild to me that this idea of a binary that theoretically seems very clear turns out is actually quite confusing, ambiguous, philosophical, even. [chuckles] JOËL: Yeah. It's definitely...you can get into some deep, philosophical questions there, language design as well. One aspect, though, that I'm really curious about your thoughts is bringing new people in who are learning a language. It's really common for people who are learning a language for the first time, learning to code for the first time to write code that you and I would immediately know, like, that's not going to work. You can't add a Boolean and a number. You're just learning to code. You've never done that before. You don't know. And then how the language reacts to that kind of thing can help guide that experience. So, do you think that truthiness maybe makes things more confusing for newcomers? Or, maybe on the other side, it helps to smooth that learning curve because you don't have to be like, oh, wait, I have a user here. I can't put that in a condition because that's not a strict true or false. I'm going to coerce it, or I've got to find a predicate method or something. You can just be like, no, put it in. The interpreter will figure it out for you. STEPHANIE: Wow. That's a great question. I'm trying to put myself in the beginner's mindset a little bit and think about what it's like to just try something and the magic of it working. Because, like you said, the interpreter does it for you, or whatever, and something happens, and you're like, wow, like, that was really cool. And I didn't have to know all of the ins and outs of the types of things I was working with. That can be really helpful in just getting them, like, started and getting them just, like, on the ground writing code. And having that feeling of satisfaction that, like, that they didn't have to, you know, have to learn all these things that can be really scary to make their program work. But I do think it also kind of bites them later once they really realize [laughs] what is going on and the minute that they get that, like, unexpected behavior, right? Like, that becomes a time when you do have to figure out what might be going on under the hood. So two sides of the same coin. JOËL: What you're saying there about, like, maybe smoothing that initial curve but then it biting them later got me thinking. You know how we have the concept of technical debt where we write code in a way that's maybe not quite as clean today so we can move faster but that then later on we have to pay it back? And I almost wonder if what we have here is almost like a pedagogical debt where it's going to cost us a month from now, but today it helps us move faster and actually kind of get that momentum going. STEPHANIE: Pedagogical debt. I like that. I think you've coined a new term. Because I really relate to that where you learn just enough to do the thing now. But, you know, it's probably not, like, the right way or, like, the most informed—I think most informed is probably how I would best describe it—way of doing it. And later, you, yeah, just have to invest a little more into it. And I think that's okay. I think sometimes I do tend to, like, beat myself up over something down the line when I have to deal with some piece of less-than-ideal code that I'd written earlier. Like, I think that, oh, I could have avoided this if only I knew. But the whole point is that I didn't know. [laughs] And, like, that's okay, like, maybe I didn't need to know at the time. JOËL: Yeah, and code that's never shipped is of zero value. So having something that you could ship is better than having something perfect that you didn't ship. STEPHANIE: On that note, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
Stephanie just got back from a smaller regional Ruby Conference, Blue Ridge Ruby, in Asheville, North Carolina. Joël started a new project at work. Review season is upon us. Stephanie and Joël think about growth and goals and talk about reviews: how to do them, how to write them for yourself, and how to write them for others. Blue Ridge Ruby (https://blueridgeruby.com/) Impactful Articles of 2022 (https://www.bikeshed.fm/369) Constructive vs Predicative Data by Hillel Wayne (https://www.hillelwayne.com/post/constructive/) Parse, don't validate by Alexis King (https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/) Working Iteratively (https://thoughtbot.com/blog/working-iteratively) thoughtbot's 20th Anniversary Live AMA (https://thoughtbot.com/events/ama-developers-20th-anniversary) 20th Anniversary e-book (https://thoughtbot.com/resources/20-for-20) Transcript: JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. STEPHANIE: And I'm Stephanie Minn. And, together, we're here to share a bit of what we've learned along the way. JOËL: So, Stephanie, what's new in your world? STEPHANIE: I just came back from a smaller regional Ruby Conference, Blue Ridge Ruby, in Asheville, North Carolina. And I had a really great time. JOËL: Oooh, I'll bet this is a great time of year to be in Asheville. It's The Blue Ridge Mountains, right? STEPHANIE: Yeah, exactly. It was perfect weather. It was in the 70s. And yeah, it was just so beautiful there, being surrounded by mountains. And I got to meet a lot of new and old Ruby friends. That was really fun, seeing some just conference folks that I don't normally get to see otherwise. And, yeah, this was my second regional conference, and I think I am really enjoying them. I'm considering prioritizing going to more regional conferences over the ones in some of the bigger cities that Ruby Central puts on moving forward. Just because I really like visiting smaller cities in the U.S., places that I otherwise wouldn't have as strong of a reason to go to. JOËL: And you weren't just attending this conference; you were speaking. STEPHANIE: I was, yeah. I gave a talk that I had given before about pair programming and nonviolent communication. And this was my first time giving a talk a second time, which was interesting. Is that something that you've done before? JOËL: I have not, no. I've created, like, a new bespoke talk for every conference that I've been at, and that's a lot of work. So I love the idea of giving a talk you've given before somewhere else. It seems like, you know, anybody can watch it on the first time on YouTube, generally. But it's not the same as being in the room and getting a chance for someone to see you live and to give a talk, especially at something like a regional conference. It sounds like a great opportunity. What was your experience giving a talk for the second time? STEPHANIE: Well, I was very excited not to do any more work [chuckles] and thinking that I could just show up [chuckles] and be totally prepared because I'd already done this thing before. And that was not necessarily the case. I still kind of came back to my talk after a few months of not looking at it for a while and had some fresh eyes, rewrote some of the things. I was able to apply a few things that I had learned since giving it the first time around, which was good, just having more perspective and insight into the things that I was talking about. Otherwise, the content didn't really change, just polished it further. I think in the editing process, you could edit forever, really. So I imagine if I revisit it again, I'll find other things that I want to change. But this time around, I also memorized my slides because, last time, I was a little more dependent on my speaker notes. And part of what I wanted to do this time around, because I had a little more time in preparing, was trying to go from memory. And that went pretty well, I think. JOËL: How did you feel about the delivery of it? Because now you had a chance to have a practice run in front of a real audience. And, as much as you practice at home in front of the mirror, it's not the same as actually giving a talk in front of an audience. STEPHANIE: Yeah. I was surprised by how the audience is also different, and the things that they'll react to is slightly different. There were some jokes that landed similarly and others that didn't land a little bit with this crowd, but maybe other parts, there was more of a reaction. So that was surprising. And I think I had to kind of adjust those expectations on the fly as I delivered whatever, you know, line I was kind of expecting some kind of reaction to. And I also, other than memorizing my slides, you know, I think had the mental capacity to focus a little more on the delivery component that you're talking about because I wasn't, you know, up until the last minute still working on the content itself, and just being able to direct my mental energy to, I guess, the next level of performance when giving a presentation. And, yeah, I would definitely give this talk again. I really liked that it was something that feels pretty evergreen, something I care a lot about. I don't think it will be a topic that I get kind of bored of anytime soon. So those were all some of the things I was thinking about in giving a talk a second time. JOËL: When you write your speaker notes, do you give yourself directions for expected audience reactions, so something like a pause for laughter after a joke or something like that? STEPHANIE: No. I think I am too nervous about presuming [laughs] how the audience will react to put something in and then have to be, like, super surprised and figure out what to do if they don't react the way that I think they will. So it ends up being that I just kind of go forth. And if I do get a reaction out of them, that's great. But not expecting it works for me because then, at least, I can control how I am presenting and how I'm showing [chuckles] up a little bit more. JOËL: So you're really working with the energy in the room then. STEPHANIE: Yeah, I think so. JOËL: Was this talk recorded? So if people in the audience want to go and watch this talk. STEPHANIE: Yeah. The first version that I gave of it is online if you search for the title "Empathetic Pair Programming with Nonviolent Communication." And this version was recorded as well. So, eventually, it'll also be up. And, I don't know, maybe I'll watch it back and [chuckles] see the difference in presentation. I would be very curious. I've never watched any one of my conference talks fully through the recording from start to end before. But I know that that's something that I could continue to improve on. So maybe one day I'll find the confidence. My other highlight that I wanted to share about this regional conference is how well-organized it was. So it was mainly organized by Jeremy Smith, and I thought he did such an awesome job. He organized a bunch of activities in Asheville for the Saturday after the conference if folks wanted to stay a little longer and just check out the city. There was a group that went hiking, a group that did a brewery tour. And the activity I chose to do was to go tubing. JOËL: Fun. STEPHANIE: Yeah, it was my first time. So you're basically in an inner tube floating down a very calm river, just hanging out. You...we were on the group, and you could clip yourself to the rest of the group so you're all, you know, kind of floating down together. But some people would unclip themselves and just go free for a little while. And, yeah, when you get too hot, you can dip into the water to cool off. And I just had such a great time. [laughs] It was almost like being on a Disney ride but out in nature, which I just, like, is totally my jam. JOËL: I tried tubing once in Texas. And the inner tubes are black, and in the Texas sun, they get really hot. So every, I don't know, 20 minutes or so, I had to get off the inner tube. It was too hot to sit on. And I had to flip it just because it absorbed so much heat. STEPHANIE: Wow. Yeah, that does sound like it would get very hot. I think the funny thing that I wasn't expecting was how hard it would be to get back into the inner tube after you had gotten in the water, at least for me, because the inner tubes were quite large. And so I couldn't get enough leverage to pull myself [laughs] back up onto it, and ended up several times just, like, flopping belly first into the inner tube and then having to, like, flop over so that I could be on my back and be sitting in it again. And other times that I had to wait a little while until the river got shallower so I could actually stand and just sit in it. So there were times that it was kind of a struggle, but 90% of it was very chill and fun. So, Joël, what's new in your world? JOËL: I started a new project at work. I'm working with a data warehouse, pulling data in from a variety of sources, getting it all into one kind of unified schema, doing some transformations on it. And then also setting up some sort of outgoing plugins to allow different sources to access that unified data. So this is not in a Rails app, but we do have a Rails app connecting to this data warehouse. Data engineering is, at least in this style, is newer to me. So I think it's a really interesting world to get into. I don't know if, technically, this counts as big data. I don't think the term is cool anymore. But five or so years ago, everybody was all about the big data, and that was the hip term to toss around. STEPHANIE: So, is this something pretty new to you? You haven't had too much experience doing this kind of data engineering work before? JOËL: Yeah, at least not with, like, a data warehouse. I think a lot of the work around data transformations, or creating unified schemas, thinking in terms of data in different stages that are at different levels of correctness...I've done a fair amount of ETL, Extract, Transform, Load, or sometimes people shift it around and say, ELT, Extract, Load, Transform. I've done a fair amount of those because I've done a lot of integrations with third-party systems. STEPHANIE: So I've always thought of data engineering as, in some ways, a separate role or a track. And I'm really curious about you having, you know, mostly been doing software development if that gives you an interesting lens to look at these problems. JOËL: So, to get the full answer, you should probably ask me again in six months. STEPHANIE: That's fair. JOËL: Initial thoughts is that there's a shocking amount of overlap between some of these ideas, again, because I've done ETL-style projects a lot. You know, if you've got any kind of Rails app and you're integrating with a third-party API, you're often doing ETL at a very small level. To a certain extent, even if you're doing, let's say, some front-end code, and you're interacting with a back end, depending on how you want to deal with that transformation of getting data from your API, you might be doing something kind of like an ETL. Designing types in something like a TypeScript or an Elm and thinking in terms of the data that you have, the transforms that you're doing has a lot of similarities to what you would do in a data warehouse. I think a lot of the general ideas apply. I know I talked at the beginning of this year articles that were impactful for me. And one of those articles that was really impactful was Hillel Wayne's "Constructive Versus Predicative Data," which is all about structuring data and when you can enforce constraints via the data structure versus when you need to enforce it via code. Similarly, a lot of the ideas from the article "Parse, Don't Validate" by Alexis King. The articles focused on designing types. But it also, I think, applies to when you're thinking of schemas because schemas and types are, in a sense, isomorphic to each other. STEPHANIE: I like what you said there about as a software developer; you've probably done this at a much smaller scale. And, yeah, like you were saying, things that you had already learned about before or thought about before you're able to apply to this different set of problems or, like, different approach to programming. Is there anything that has been challenging for you? JOËL: Yes, and it's a weird one. Because we're working with enterprise systems, navigating the websites for these enterprise systems and the documentation for them is not a pleasant experience, trying to get a feel for how the system is made to work. It's just so different when you're used to tools and documentation written by the open-source community. Even third-party tutorials and things it's never, like, oh, here's a great article where you can scan and find the thing that you want. It's, hey, I'm a consultant guru on this thing. Sign up for my webinar, and you can have a 15-hour course on how to use this tool. And that's not what I want to do. I just want give me the five-paragraph blog post on how to do data imports, or how to set up a staging area for data, or something like that. STEPHANIE: Right. You're basically being asked to develop skills in using the enterprise software rather than more general skills for the problem or task; it sounds like. Because apparently, there are people making a business out of teaching other people how to use or navigate the software. JOËL: And I think that's fine. I love that people are making businesses of teaching these. But just the way things are structured, information is not generally as available for this large enterprise software as it is in the open-source world, and even when it is, it's just different patterns of access. So even you go to a particular technology's website, and it's all marketing copy. It's all sales funnel and not a lot of actually telling you really what the technology does. It's all, like, really vague, you know, business speak on, you know, empowering your team, and gathering insights, and all this stuff. So you really do a lot of drilling down. And what you need to find is the developer site. That's where you get the actual tech documentation. Depending on the tech, it's more or less good. But yeah, the official website of the technologies is just...it's not aimed at me as a developer. It's speaking to a different audience. STEPHANIE: That is interesting. I didn't realize that once you are, you know, working on a data warehouse, it is because you are consuming so many different external sources of data, and having to figure out how to work with each one is part of the process to get what you need. JOËL: So there's the external services but the data warehouse itself that we're using is an enterprise product. STEPHANIE: Got it. JOËL: So, just figuring out how this data warehouse works, it feels like it's a different culture, a different developer culture. STEPHANIE: That's cool. I'll definitely ask you again in a few months, and I look forward to hearing what you report back. So the other topic that I wanted to get into today is reviews, specifically self-reviews. To be honest, our review cycle is happening right now. And I have very much procrastinated [chuckles] on writing them until, you know, one or two days before. So I came into our conversation today, like, in that mind space of thinking about my growth, and my goals, and that kind of stuff. And it got me thinking that I don't hear a lot of people talk about reviews, and how to do them, how to write them for yourself, how to write them for others, how people approach them. Though I would guess that the procrastination part is pretty common, [chuckles] just based on what I'm hearing from other folks on our team too, and what they're up to for the next couple of days before they do. Joël, have you written your review yet? JOËL: So it's interesting because this review cycle has a few different components. You write a self-review. You write a review of your manager, and then you write a review of several of your peers who have nominated you to write a review. So I've done my own review. I've done my manager's review. I've not completed all of my peer reviews yet. STEPHANIE: That's pretty good. That's better than me. I've only done my own. [laughs] So, yeah, the deadline is coming up. And I'll probably get back to it right after this. I'm curious about your process, though, for writing a self-review. Do you come into it having thought about how you've been doing so far in the last six months or so? Or, when you sit down to write it, are you thinking about these things for the first time in a while? JOËL: Combination. So I think I do come in without necessarily having, like, planned for the review cycle. That being said, throughout the year, I try to build a fair amount of, like, personal self-reflection, professional self-reflection at various points throughout the year. So I'm not coming into the review cycle being like, oh, I have not thought about professional growth at all. What have I done this year? I think one thing I haven't done quite as well is when I'm doing these moments of self-reflection on my own throughout the year, writing down notes that I could then use to apply when the review cycle comes up. So I am having to rely on memory on, like, oh yeah, last month, when I kind of sat down and thought about areas that I want to improve in or areas that, like, what are my goals that I want to have? And I just commit that to memory. So, yeah, I think live in the moment; now that you've asked me this question, you've made me think that maybe I should be taking more regular notes about this. STEPHANIE: One thing I've been really liking about the software that we're using for reviews and other professional growth things is...it's called 15Five. And you can give your co-workers shout-outs using this tool. And as I was writing my review, I could actually open all of the kudos and shout-outs that I received from my peers and just remember some of the things that I worked on or a lot of the things that other people noticed. I tend to sometimes have a hard time remembering some of the smaller things that I've done that made an impact, but other people are usually better about pointing that out than I am. [chuckles] And that has been really helpful because it's, yeah, nice to see like, oh, like, you know, so and so really appreciated when I paired with them on, you know, debugging this thing. And maybe I can pull that into something that I'm writing about the kind of mentorship I've been doing in the last few months. JOËL: How do you feel about the aspect where you have to then give feedback on colleagues? STEPHANIE: I really value and enjoy this aspect because most of the time, I am just gassing my colleagues up [chuckles] and writing, you know, really encouraging things about all of the awesome work that they're doing. So, for me, it actually feels really good. And I was thinking a little bit about my approach to reviewing my peers and review culture in general. I have worked at companies where we have had a very, like, healthy and positive review culture. So it happens often enough that it's become normalized. It's not a really scary thing. And I also like to think about feedback in two types, where you have feedback that you want to give someone so that they can change behavior in a way that helps you work with them better, and then feedback you have for someone for their growth. And once I separated those two things, I realized that really, the former, if you're, you know, giving someone constructive feedback because you maybe would like them to be doing something different. That's not necessarily what you want to be writing in their annual review. Those things are usually better communicated in a more timely manner, like, right when you are noticing what you might want to be changed. And so then when you are doing reviews, like, you've hopefully already kind of gotten all of that stuff out of the way. And you can just focus on areas of growth for them, which is the fun part, I think, in reviewing peers because, yeah, you can give some suggestions to further support them in, like, where they want to go. JOËL: I like that distinction between just general growth, suggestions, and then interaction suggestions. And just to give an example, it sounds like interaction suggestions would be like, "Oh, when we pair, I would like it if you used this style of communication from, let's say, nonviolent communication. Here's a talk; go watch it." STEPHANIE: [laughs] Yeah, I did talk on this; go watch it. There used to be a framework for reviews that I've done before that I actually don't quite like. It's the Stop, Start, Continue framework where you answer questions about, okay, what should this person stopped doing? What should they continue doing? And what should they start doing? And the things that you would put in stop, I think, are probably what you would want to have communicated in a more timely manner, like, not necessarily it happening, you know, really divorced from whatever behavior you might be asking. And, in general, I think focusing on what you would like others to be doing instead is usually a better approach to handling that kind of feedback just because it avoids making someone feel bad about having done something wrong and, instead, kind of redirecting them into what you would like them to be doing. JOËL: So you're saying if you have something in the stop category, let's say stop interrupting me all the time when we're in meetings, you're saying this is something you prefer not to bring up at all or something that you prefer to bring up one on one and not in the context of review? STEPHANIE: Something to bring up one on one. Ideally, pretty soon after, that might have happened. It's a little more top of mind. And then you don't end up in that position of maybe misremembering or having the other person misremember and having to figure out, like, who was in the right or in the wrong in understanding how that interaction went. Especially if you're able to do it a little sooner after it happened, you can point out, like, hey, this happened. And instead of framing it as please stop interrupting me, you could say, "Could you please make some space for some folks who've been a little more quiet in the meetings to make sure that they've been able to share?" Still, I think once you've made more space to give that kind of constructive feedback when you are writing reviews, you can then, like, focus on the growth aspect and not the redirection of how others are doing their work. JOËL: That makes sense. So, what would be an example of the kind of feedback that you like to give to other people in the context of a review? STEPHANIE: Yeah, I think especially if I know what someone is wanting to focus on, right? If I'm working with someone, hopefully, we've kind of gotten to talk about what they like to work on, what they don't like to work on, what they are hoping to spend more time doing, or yeah, just their hopes and dreams for their professional [chuckles] development, being able to point out some things that they maybe haven't thought about trying it I really like to do. I was thinking about a time when I gave a co-worker some feedback as a mentee of theirs where they had been really awesome at providing information to me about things that I was unfamiliar with. But one thing that I was really hoping for was more tools to figure things out on my own. So instead of sending me a link to some documentation, maybe helping me figure out how to search for the documentation that I'm looking for. And that was something that I could share with them because I knew that they wanted to work on their mentorship skills and an opportunity, I think, for them to take it to a level where it's closer to coaching and not just providing information. JOËL: That makes a lot of sense. Maybe flipping it around, is there a point in time where you've received a review feedback that has been really valuable to you or really helped you hit the next level in your career? STEPHANIE: I really appreciate feedback that encourages me when I'm maybe a little bit too timid to go seek the things out myself. So there were times when I received some feedback about how great of a leader I could be before I thought I was ready to be a leader. And they pointed out the qualities of leadership that I had demonstrated that led them to believe that I would be ready for a role like that. And that was really helpful because I don't think that was even necessarily a short-term goal of mine. And it took someone else saying, "I think you're ready," that made me feel a lot more confident about opening that door. I guess this is all to say that I really love review season because of, you know, all of the support I get from my co-workers. And, yeah, just remembering that it's not just a journey I have to take all by myself, that the point of working with other people is for all of us to help each other grow. JOËL: I think something that you mentioned earlier really connected with me, the idea of trying to give feedback in the...even, like, feedback that's about changing or improving, phrasing it in a more positive way, or at least framing it in a more positive way. So here's an opportunity for growth rather than here's the thing you're doing wrong. Because that reminds me of two pieces of review that I got when I was a fairly junior developer that have stuck with me ever since. And one of them was really a catalyst for growth, and the other one kind of haunted me. So this first one I got, someone in a review just mentioned that they thought that I was just generally a slow developer, just not fast at writing code. Not a whole lot of context; just that's who I was. And, in a sense, it was almost like I'd been given this identity, like, oh, I am now Joël, the slow developer. And I didn't want that identity. So I'm kind of like, I want to refuse to accept it. But at the same time, there's always that self-doubt in the back. And now, anytime I'm on a project with someone else, I'm comparing, oh, am I shipping stories quite as fast as someone else? And if not, why? Is it because I'm a slow developer? Or if I'm having a rough day and I'm not getting the ticket done that I was hoping to get done by the end of the day, you know, you just get that voice in the back of your head that's like, oh, it's because you're a slow developer. Someone called that out last year, and they were right. So, in a sense, it kind of haunted me. On the flip side, I once got some feedback talking about an opportunity for growth. If I focused on working in more iterative, incremental chunks, it would help have a smoother workflow and probably help me work faster as well. And that was really kind of an exciting opportunity. It's also stuck with me for years but not in the sort of haunting sort of way or this, like, bring in self-doubt but more in terms of opportunity. Because now I'm always like, oh, can I break this down into even smaller chunks? Would that help me move faster? Would that help me be less blocked on other people? Would that be easier for our QA team? Would this be easier for review for my colleagues? Just a lot of different opportunities for benefits with working in smaller iterative chunks. And, for years, I've just been kind of honing that skill. And now, looking back over, you know, a decade of doing this, I think it's one of the best skills that I have. And so, in a sense, I feel like both of these people that left me that review, in a sense, they're trying to get me to maybe have a slightly higher velocity. But they're different approaches, radically different in terms of how it impacted me as a person. STEPHANIE: Yeah, I am really glad you brought that up. Because I definitely have also received, quote, unquote, "constructive feedback," but maybe wasn't phrased in the right way, that also haunted me. And it doesn't feel good. I think that that sucks. That person wasn't really able to frame it in a way that pushed you to progress in the positive way that you mentioned with learning to work incrementally. And in fact, I almost think that the difference in those two phrasings is encapsulated by a framework for giving feedback that's actionable, specific, and kind. So suggesting you to work incrementally is all of those things, especially if they know that you do want to increase your velocity. But you're being supported in doing it in a way that is positive and growth-oriented as opposed to, like, out of fear that other people think that you are a slow developer. And, you know, that's certainly a way that people are motivated. But I would say that that's not the way that we want to be motivated. [laughs] JOËL: I'm glad we're having this conversation because I think it just reinforces to me just the value of good communication skills for developers. And, you know, you can see that when developers have to write documentation, or even things like comments or commit messages. You see it when developers write blog posts. So it's really valuable to work on your communication skills in a lot of these technical areas. But reviews are a very particular area where it's easy to maybe have not the impact that you wanted because you communicated a core idea that's probably right, but just the way it was communicated was not going to have the impact that you're hoping for. And so getting good at communicating specifically in the area of reviews, which I assume most of us in the software industry are doing on a semi-regular basis, is probably a good tool to have in your professional tool belt. STEPHANIE: Absolutely. JOËL: We recently hit a big milestone at thoughtbot, where thoughtbot turned 20 years old in early June. And so, throughout June, we've been doing a lot of fun internal things and some external things to celebrate turning 20. And one of those is we're hosting a live AMA with a variety of thoughtbot devs. That's going to be on Friday, June 23rd, so a couple of days after this podcast goes live. So, to our listeners, if you're listening to this, in the first few days after it goes live, you get a chance to join in on the live AMA and ask your questions of our team as we celebrate 20 years. There's a blog post with all the details, and we'll link to that in the show notes. STEPHANIE: One other thing that I think we're doing that's really cool for our 20th anniversary is we published a short ebook with a curated collection of 20 hits from our blog, the thoughtbot blog, over the course of its history, some of the more popular and impactful blog posts that we've ever published. So I highly recommend checking that out. You know, the thoughtbot blog is such an awesome resource. And I discovered a few things that I hadn't read before on the blog from this ebook. So that will also be linked in the show notes. JOËL: I mentioned earlier how one of my opportunities for growth through review was getting better at working iteratively. And, a couple of years ago, I took a lot of the lessons that I'd learned over the years of getting better at working iteratively, and I put them in a blog post, and that blog post made it into that 20th Anniversary ebook. So we can probably link the blog post itself in the show notes. But also, if you're picking up that ebook, you'll get a chance to see that article on my lessons learned on how to work iteratively. STEPHANIE: Awesome. On that note, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
Joël has a bike shorts update; Stephanie has a garden one. Often, power is centralized within the dev team. This is usually because they are the only ones able to execute. Sometimes this ends up interfering with team processes and workload. Joël is a fan of empowering other teams to do things themselves. Strangler Fig Pattern (https://shopify.engineering/refactoring-legacy-code-strangler-fig-pattern) What Being a Staff Developer Means at Shopify by Rose Wiegley (https://shopify.engineering/what-being-a-staff-developer-means-at-shopify) End-User Programming (https://www.inkandswitch.com/end-user-programming/) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: So, in a recent episode, I had mentioned that I was going to go on vacation on a bike trip and that I had purchased a pair of bike shorts to try out on that trip to see if that would help. And, wow, that was a great purchase. It literally saved my butt. STEPHANIE: That's awesome. I'm really glad that they worked out for you. JOËL: Still sore. This was a five-day biking trip. And I think day two was the worst, but after that, things got better. But the shorts definitely helped. STEPHANIE: I think my favorite part about us talking about biking and bike shorts is that we're finally living up to the name of our podcast. [laughs] Turns out that bikeshedding is actually even more, bikeshedding when it's about actual bike stuff. And a listener named James even wrote in with some pro tips about, you know, how to care for your bike shorts and, you know, have a comfortable biking experience. And gave some good tips for me on some longer rides to check out near me in Chicago. JOËL: So it sounds like there's some crossover between the software developer community and bike enthusiasts community who also tune into this podcast. STEPHANIE: I do think that we have gotten tweets before from, I think, like, the motorcycle Twitter tagging us @_bikeshed, perhaps maybe trying to tag a different account but, yeah, ended up in our Twitter inbox instead. JOËL: Now we just need some sweet, sweet bicycle sponsorships. So, Stephanie, what's been new in your world? STEPHANIE: I have a garden update. Last year, we purchased a small fig tree from the internet. It turns out that you can get little fruit trees delivered to your door. And this was, I think, around the fall, so it was getting a little cooler. And here in Chicago, we have to bring some of our plants inside to overwinter. And so we brought the fig indoors, and it's maybe, like, two or three feet tall. And, you know, over the few months, we were just, like, caring for it. And I was really excited to see that it had started fruiting several months ago. And I got to show it to all of my co-workers in a call. I, like, picked up this kind of large pot with our little fig tree, and I, like, held it really close to my camera and tried to point out the fruit to the other people on the call, which I realized was perhaps not a very effective way to show off my plants. Like, you could just take a picture and send it in Slack. And I was like, yes, I could have done that. But yesterday (Now our fig tree has been outside for a little while since it's warmer.) I noticed that they were ripe, and I got to harvest our figs and eat them, and they were delicious. And I got to update the team on my little fig adventure. And this time I did take pictures of the fruits and sent them in Slack instead of trying to bring this tree in from the outdoors. JOËL: That's exciting. Because I'm a fan of the design pattern, I have to ask, is this a strangler fig? STEPHANIE: It's not a strangler fig, though I have seen one in the wild on a trip to Florida. I saw a really big strangler fig, you know, completely, like, enveloping another tree, and that was really cool. If you ever get to see one in person, I think it's just, I don't know, just really amazing how nature works. JOËL: I did not realize they were wild in Florida, something to keep an eye out for next time I'm there. STEPHANIE: Definitely. So, in a recent retro on my client team, we were discussing the one-off requests our team has been getting from the folks over on the sales and client support side. Oftentimes, this involved running a script in our production console to fix some issue that a customer was experiencing. And we were talking about what we could do to make this process a little more automated, make it a little less time-consuming on our end. Even though it would just take a few minutes to run this script, we were seeing that we were getting this request repeatedly. I'm curious if you've kind of been in this situation before where dev work is required and kind of eating into time that we are trying to be delivering on other feature work for similar one-off requests or to support other folks at the company. JOËL: Yeah. I think it's a pretty common pattern that I've seen. And I think sometimes it can actually start from a healthy place. If you're taking very much of an MVP philosophy and you're building a small version of your product to start with, you're not going to have a whole suite of admin tools available. You might not even have any admin people. It might just be a founder and a technical co-founder. And so, for the first few hundred customers you have, maybe the way you make changes is by loading up the Rails production console and making a change. And that's good enough, but that doesn't scale. STEPHANIE: Yeah. You bring up a good point that I think one thing that we get to experience as consultants is seeing many different companies at different stages in their business. And I think I've seen this issue in many different iterations based on the size of the company, right? So you were saying for an MVP product, there's no admin support at all. Maybe you have a project that is now thinking of how to introduce a little bit of admin tooling and might reach for something lightweight like a gem. I've also seen custom admin dashboards, and that being its own namespace and having all of that feature set hand-rolled, and then maybe some other company might opt for a Software as a Service solution. JOËL: Yeah, there's a lot of different implementations that happen at various stages of companies. I think one thing that does seem to stay pretty constant, though, is oftentimes; other teams don't have the tools they need to make the changes they need to. So, if you have a customer service person and they're receiving a complaint or they're having to make a change, they're not always empowered to make the changes they need to. They need to talk to the dev team, who then need to make changes. And the dev team don't really want to spend their day doing admin work. They are incentivized to ship features. And so both sides are unhappy. And it kind of comes from a sort of fundamental, I think, over-empowering of the dev team and kind of a disempowering of some of the other departments within the company, if that makes sense. STEPHANIE: Yeah, that's interesting because I don't think it necessarily is intentional, the way that that happens, right? It's not like you start building a product, and you are saying, "Okay, we only want to give devs the power to change all of this stuff at the production level." It's just something inherent, I suppose, to the work that we do. And there's a lot of active effort that needs to be taken to spread some of that empowerment around. JOËL: Yeah, generally, it is not some sort of, like, nefarious corporate politics that's happening where the CTO is, like, hoarding all the power, or it's a turf war or anything like that. Like you said, it's kind of an emergent property. As developers, we're often used to being sort of ultra-empowered to do what needs to be done. In general, development teams are highly respected within companies, and so people listen to them. But also, in order to do their job, they need to have access to a lot of things. So you often have production access to all the things and the admin credentials. And if there's something that doesn't work, you write code, and you can change the sort of fundamental underlying platform that you're working with. And so you're generally empowered to make the changes you need to make your life better or if you're blocked on something. And that's not necessarily true for other departments who are working in the system that we're building. STEPHANIE: Yeah, it's kind of interesting the duality that you have identified where we do have all of this power or capability to change the system. But you had mentioned earlier that sometimes it actually gets in the way of our work, that it can be a drag to do if we have other competing priorities, and that those mundane tasks end up being something that we also don't enjoy doing. And so, like you're saying, like, no one is quite happy. I wonder at what point you, as a developer, having repeatedly been asked to do these kinds of tasks for other departments when you, would start advocating for building tooling. JOËL: I don't think there's a kind of a clear dividing line, like, oh, after three requests, you must build a dashboard. It's probably more about just general communication with the other teams. I like to think of it from kind of two perspectives. From the perspective of the developers, how can we keep them efficiently working on what they need to prioritize, which is typically new feature development? And then, from the perspective of other teams, how can they be empowered to do the work that you need to do without getting blocked? Because just like the dev team doesn't like to get blocked on all sorts of things, other teams don't like it either. And so, how can we make sure that other team members within the company are empowered to do their work as efficiently as possible? STEPHANIE: Yeah, that's interesting. I think as an IC, I've been in different positions, depending on the context of my work. There have been times when I've been happy to help with that kind of request, right? Because I know that I'm unblocking someone else. I'm facilitating their work. And they usually appreciate it too. And so maybe if that's still the case and that there's not necessarily any pain that comes with that being just the process that it is from both sides, like, that's perfectly fine. But then it's totally fair for, you know, either party, once they do feel like it's blocking other work, to start looking into maybe how much time you're spending on these one-off requests, especially if it's being spread around to other team members. You know how much effort you're making, but, like, a manager might actually be more aware of how it's affecting multiple folks on the team and wanting to figure out, like, how that sits in with the other priorities that the team is working on. JOËL: Yeah, I'm glad you mentioned talking to other people because I might be quite happy to say, "Oh, I'm going to go and, you know, go into the database and make a small change." But just because it's easy for me to do and I can take, you know, 10 minutes out of my day to do it, doesn't mean that that experience is good for, let's say, a customer service person who had to get blocked or had to ask someone else to help to move this ticket forward. When if it was something they could do themselves, that would have been a much better experience. So, even though it's a very fairly, you know, cheap request and because I don't get them a lot, I'm happy to do them, it's maybe not a good experience for my customer service colleague. So, like you said, it is important to get people's experiences on all sides. STEPHANIE: One thing that I have seen a lot is for these things to start as configuration in a YAML file that requires developers to change and then commit to the codebase whenever, you know, maybe it's, like, a list of products or a list of prices, something that is, you know, really the business domain. And yet we are hard coding it and, like, codifying it into our source control. JOËL: Oof, yes. I have been in those projects, yeah. Now, every time you want to make a change, a business person has to reach out to the dev team, and then you have to make a code change, and then you have to deploy it. And that just becomes a whole thing. And then they come back to you the next day and say, "Oh, actually, we talked about it, and we want it a little bit differently." And you have to go through that process again. STEPHANIE: I think we reach for that just because we think it's faster maybe to set up, you know, some kind of, like, lightweight configuration file, rather than if you're working in Rails, you know, setting up a whole MVC for whatever thing you're trying to configure. And I'm curious if you think that's true or not. JOËL: I think it depends. Sometimes it can be because this data feels very static, kind of hard-coded. And so it's not a thing you would necessarily want to have. In a database, it's more like a constant that you would have in your source control, except that then you find out that your constant is not quite as constant as you thought it was. And I think maybe that's okay. Writing software is all about kind of discovering the problem in the domain as it evolves and trying to not over-engineer things ahead of time. So, if we have a small set of values, maybe they're U.S. states that you deliver to or a small list of products or something that you feel is relatively hard coded, maybe it starts as a constant array hard coded into Ruby, maybe it is a YAML file that you load. Then, over time, there comes a point where you decide this should be a database table, and if it needs to be sort of pre-seeded, then there's a mechanism for that with database seeds in Rails. STEPHANIE: Yeah, that's fair. I find it so interesting because most of the time, I've not seen that transition happen, right? It almost feels like some form of the bystander effect where everyone is just, well, I'm adding just one more thing. So I don't want to make this really big change now. JOËL: And that's true for everything in code, right? You say, "Oh, this deeply nested condition, yeah, it should probably be restructured. But I'm just going to add, you know, an eighth nested level in there. And, like, eight is probably the limit, but mine is going to be the eighth, so it's going to be good." And then somebody comes in and says, "Well, you know, nine is not that bad, but the next person probably should refactor it." And then it's a mess. STEPHANIE: Yeah, it's kind of like the entropy of code, I suppose, [laughs] where, you know, we had said it requires a lot of active energy and effort to make those changes to support other folks in different departments of the company. And I think that's, like, one very common area that we see things starting as configuration but then end up being something that you are needing to support in changing. And I wonder if maybe that is a signal in itself, right? If you are getting this information from another team, like, someone external to the development team, I wonder if that's kind of a clue that this is something that should be reconsidered about whether you start with it being hard-coded. JOËL: That's an interesting thought. There's a sense in which I think these always come from places external to the development team because it's a form of kind of product research when you're trying to understand what the features need to be, what this needs to happen. Unless this hard-coded data is purely structural or internal values, but it rarely is. There probably is a broader discussion to be had about the use of any sort of hard-coded data in a configuration file in a Rails app versus just always starting with a database table. One thing that's nice about always having a database table is that if you ever need to connect it to other data in your system, now you can do things like table joins, where you can't join your users on some kind of YAML array, or you have to do some sort of Ruby Enumerable logic. You can't just do it in SQL. STEPHANIE: Yeah. This is a bit of a tangent, I think. But that reminds me of when I worked at a product company where we had a very robust data warehouse, and all of that information was available to teams on the marketing side and on the data science side. And I actually really liked that because they were able to, you know, construct their own dashboards and queries to get the things that they need. And I've certainly seen what you're saying, this pretty important business information being hard-coded, and that ends up being less accessible, right? And less insightful, really. One other area of this topic that I think I've also bumped into before is specifically a QA engineer or, like, a QA team and empowering them to be able to do their jobs. Oftentimes, I've noticed that QA environments are not as well-maintained as maybe they should be, where the data that's seeded or, you know, kind of overtime in this environment is a little wonky. I've also experienced, while working on a feature, kind of having to go back and forth between whoever is helping QA my work telling them, like, "Oh, this isn't finished yet. So, like, don't worry about this that you're testing," or, you know, "Actually, that does look wrong. But let me look into it over on this end." And I found it sometimes difficult to navigate because I want them to be more empowered to test their feature without that uncertainty over whether something is intentional or actually broken. JOËL: In this case, do you think it's more about communication between development and QA, clear acceptance criteria, or clear descriptions of what changes have been pushed up for review and what's not in scope? Is that where you're headed? STEPHANIE: I think that's a part of it. But I actually think there are more technical considerations, especially in terms of whether our environments all align in terms of the data we're expecting, right? Does our dev environment kind of look like our QA environment, which looks like our production environment? Because I've certainly been in projects where that's, like, all over the place, and that really messes up the different expectations we have. We all know the "Oh, it worked in my local" [laughs] response to when things come up in other environments that are unexpected. And I wonder if there is more attention that we should be having towards making sure that just because this environment is not the main one that we're working in as developers, that people who are having to use it have an equally good user experience. JOËL: I like that you brought up the term user experience because oftentimes, as developers, and just, I think, product teams in general, we're trying to make something good for the customers of the application. But there are a lot of other people that have to interact with it in sort of more ancillary roles; like you mentioned, it might be QA. It might be customer support. It might be business development. And they're not the customer. And so because of that, they're often kind of a second thought or even sort of no thought at all. And so they do their jobs as best they can with what they've got, and sometimes get really creative getting around some of the hurdles that are in place. But we can often, with very little effort because the bar is so low, make these people's lives a lot better by applying just a little bit of the same approach that we would use to make software great for a customer to use for teammates in these other roles. STEPHANIE: Yeah, absolutely. Especially because we have that line of communication open with them, and, like you said, they are also our users of our applications. And especially for QA folks, too, in some ways, they're the first line of defense of our users, right? They are a resource for us to know if the customers will eventually have a poor experience or not. And I was thinking about that back-and-forth communication I mentioned with QA, you know, trying to explain, like, oh, this isn't finished yet, so maybe, like, you should not expect this to happen. But, oftentimes, that perhaps is a signal that we haven't thought about the way that we're developing our feature to be able to be released to customers in a more incremental way. Or we might be hand-waving over something that ends up being a bug later on. JOËL: Definitely. For myself, I see that as a... code smell is maybe not the right term here, but maybe acceptance criteria smell. If I'm trying to write out some acceptance criteria, and I'm having to say, like, "Oh, but, like, ignore this, and, like, pretend this doesn't exist. All of these, like, weird edge cases and exceptions we're trying to put in, are oftentimes a sign that maybe the work was not scoped correctly. STEPHANIE: I'm curious, in your workflow, will you just make those improvements if you have the opportunity to? Or do you end up bringing that to the team or creating a ticket for it? How does that fit in when you identify areas that could be improved? JOËL: I think it depends on the team's current workload. Oftentimes, if it's just something small, it's something I can just slip into my day, and it makes somebody else's life easier, that's great. Otherwise, it can be a thing that needs to be brought up with the team in general. And then it's the thing that we prioritize, and we put it in the backlog because, like you said, the main users of our app are customers. But all of these other teammates are also users of our app in other ways, and so they need certain features to get their job done. And so it's worthwhile to, I think, at a product planning level, take those into account and prioritize them with the customer-facing things. And sometimes, because those other teams don't have as much of a voice at the table, it's up to us as developers because we sometimes have that direct communication where we're talking to them and sort of going back and forth about, "Oh, can you change this in the database for me?" or "Can you do this?" And it can be up to us to champion these other teammates' needs with the team and with the product organization in general. STEPHANIE: Yeah, I really like the way you put that. I think you used the word champion. And I've seen this also go the other direction, where we add more processes in place, where the direct communication that needs to be gatekept a little bit through a manager because the manager is trying to protect the time of the team. And that is one way to handle the issue of these requests taking too much of the team's time. But I think at some point, as an IC, you also have the agency to champion or advocate for how you use your own development time. And that reminds me of something I heard from Rose Wiegley over at Shopify about what it means to be, like, a staff or a senior developer, and that is sharing that I'm going to do this, and this is why. And that means that I won't have time to do this other thing that I may be committed to earlier. But you know, these are my reasons. And if anyone sees any problems with that, let me know. And I've been thinking about that a lot in terms of figuring out how to do the kind of work that I value. And for you and me, that does sometimes mean building those tools to empower people who aren't developers. But that is, yeah, just a way that we can assert a little bit of that agency rather than having to get the buy-in to even consider setting time aside for that work. JOËL: Yeah, I think some of the really fulfilling work that I've done has been just sometimes taking a morning and, quote, unquote, "pairing" with, like, a business development or a customer service person and just saying, "Hey, can I just sit with you while you process this kind of request or problem that you're trying to do?" And then just really seeing what they do and all the steps and being able to ask a lot of questions and kind of putting my product developer hat on. And because then I know, internally, all the things that are happening, I can quickly see, oh, okay, you're- having to do these, like, five steps to get around this really annoying thing that's just, like, a rough corner that we have that I can, like, just easily smooth the way, you know, with a 10-minute one-line fix. I'm going to go and do that, and, you know, by the afternoon, that's already done, and that's saved them so much time or so much annoyance because it's not always time. Sometimes it's just annoyance. And their life is better. And I put very little effort into it. Most of it is just taking the time just to talk to each other and to try to understand each other. So I think we brought up the idea in the beginning of trying to empower other teams to not sort of centralize all the ability to execute on change within the development team. And sometimes, you can go to fairly extreme lengths to that. One that I've seen is the idea of end-user programming or end-user development, where the using the software rather than the team developing it has some sort of way where they can sort of customize or build on, or sometimes even script or -code -their experience. Is that something you've ever had to deal with or interact with on a project? STEPHANIE: Yeah, it's really interesting that you brought that up because I had mentioned going with a SaaS solution earlier as something that I've seen before. And that reminds me of when I worked on a client project where we were using Freshsales to integrate with the business domain of the client. And this would eventually be the main software that the sales team would use. And the reason that we went with Freshsales was because it allowed for a lot of that custom configuration and workflows that they could create for themselves for their needs. Though ironically, as we were kind of butting up into the limitations of Freshsales and how it didn't necessarily work for the way we were representing our data, we kind of joked that we almost wished we had to build the tool from scratch ourselves. So I think there are trade-offs there, you know, folks had done a lot of research to figure out the right SaaS solution for this project that we were doing. And yet, you know, inevitably, like, there were some cons with the third-party and how we were able to integrate with it. And it was actually also replacing something that had been built in-house and had become difficult to maintain or something that the company decided that they didn't want to maintain anymore. So I hate to say it, but I really think it [laughs] depends. JOËL: And now you're getting into the classic build versus buy dilemma for chunks of your software. STEPHANIE: Yeah, absolutely. JOËL: I think a way that I've seen, and this happens in a kind of a smaller sense, is providing escape hatches for data. And so maybe you've got a couple of small dashboards, or you've got just a lot of things that happen in your system. And you don't have the development time, or you don't want to prioritize that time right now to build something custom for maybe your business development team. But you provide certain reports that can be exported as CSV or Excel, which then the business development team will load into Excel and do the work that they need. And now they're empowered to do what they want instead of having to ask for more information or just being limited to what was on that web UI. Similarly, sometimes, when you're able to Import a CSV, I've seen this happen a lot, where in software that's not built just right for a customer service team, they'll often export a CSV of data, put it into Excel, manipulate it the way they really want it to be, and then re-import it into the system. And so that can be a great way to temporarily empower people. I think it's also a product smell. Oftentimes, there's a fundamental flaw of the way that your product works because your team is trying to go around it. It's so bad. But as a shorter-term solution, that can be great. STEPHANIE: That makes me think that Excel is the real end-user programming software. JOËL: It really is. It really is. I do really like the idea of end-user Programming, though. And rather than developers or even product people having to decide how our software should work for our users, shifting that to the masses and letting them have all of that empowerment and agency that we're talking about. There's a technology research lab called Ink & Switch, and they build a lot of really cool end-user programming tools. I think I've seen some, like, note-taking software, that they've done, and just other research into why it's important and how it can impact users. And I have read a little bit of their work, and I think it's really cool. So I'll be sure to add that to our show notes. JOËL: I think even as developers, we like some of these ideas of end-user development. We have that a lot in our tooling. But then, even when we interact with other people's software that we don't own...because we're used to interacting with our own software, we own it. We can change anything we want. We've got complete freedom. But the moment we interact with somebody else's software and, of course, it doesn't work 100% the way we need it to, it is sometimes nice to have sort of ways to hook into it so that we can get the things we want and then maybe do some extra manipulation on our own. And APIs are often how we do that. And so the equivalent of providing an API for another developer, well, what is that for our other teams? STEPHANIE: Yeah, great questions to consider. JOËL: You know, it could be a CSV export. It could be maybe there's some easy way to connect to a Zapier plugin. And now, you know, they don't need to ask the dev team, "Oh, we want to receive this notification email internally when this event happens. They can just connect to a Zapier plugin and have it send an email or do something in Salesforce or all these other things that are helpful in their workflows but that we've not taken the time to build into the core software. And now they're empowered to do their work and not blocked on us. STEPHANIE: That's interesting because as you were talking about that, it made me think of development tooling that we get to integrate with and how those APIs are usually very flexible. And let us decide what we need and ask the API for that as opposed to it dictating it for us. And, you know, if that's something that we get to enjoy, then, yeah, we should certainly think about how you can spread that to others. JOËL: I love that. On that note, shall we wrap up? STEPHANIE: Let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeeee!!!!!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
Stephanie is joined by very special guest, fellow thoughtboter, Senior Developer, and marathon trainer Mina Slater. Mina and Stephanie had just been traveling together for two weeks, sponsored by WNB.rb for RubyKaigi in Matsumoto, Japan, and together, they recount their international adventure! RubyKaigi (https://rubykaigi.org/2023/) WNB.rb (https://www.wnb-rb.dev/) Understanding the Ruby Global VM Lock by observing it by Ivo Anjo (https://rubykaigi.org/2023/presentations/KnuX.html#day1) gvl-tracing (https://github.com/ivoanjo/gvl-tracing) Justin Searls' RubyKaigi 2023 live coverage (https://blog.testdouble.com/field-reports/ruby-kaigi/) Prioritizing Learning episode (https://www.bikeshed.fm/362) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn and today. I'm joined by a very special guest, fellow thoughtboter Mina Slater. Mina, would you like to introduce yourself to our audience? MINA: Yeah. Hi, everyone. I am Mina. I am a Senior Developer on Mission Control, which is thoughtbot's DevOps and SRE team. STEPHANIE: So, Mina, what's new in your world? MINA: Well, I start marathon training this week. So I hope that this conversation goes well and lasts you for three months because you're probably not going to see or hear from me all summer. STEPHANIE: Yes. That sounds...it sounds hard, to be honest, marathon training in the summer. When I was doing a bit more running, I always thought I would wake up earlier than I did and, you know, beat the heat, and then I never would, and that really, like, was kind of rough. MINA: Yeah, actually, I was thinking about my plans for today. I didn't wake up early enough to run in the morning. And so I was calculating, like, okay, by midday, it's going to be too hot. So I'm going to have to wait until, like, 6:00 p.m. [laughs] STEPHANIE: Yeah, yeah. Or, if you're like me, there's a very real chance that you just skip it altogether. [laughter] MINA: Well, I have a deadline, so... [laughs] STEPHANIE: That's true. When is your marathon race? MINA: This is actually the first year I'm doing two in a calendar year. So I'm doing Berlin in September. And then, three weeks after that, I'm going to run one in Detroit. STEPHANIE: Nice. At least you'll be ready. You'll, like, have done it. I don't know; it kind of sounds maybe a bit more efficient that way. [laughs] MINA: Theoretically. But, you know, ask me in October. I'll let you know how it goes. STEPHANIE: That's true. You might have to come back on as a guest. [laughs] MINA: Just to talk about how it went. [laughs] STEPHANIE: Yeah, exactly. MINA: So that's what's new with me. What's new in your world, Steph? STEPHANIE: So, a while back on a previous Bike Shed episode, I talked about joining this client team and, in their daily team syncs, in addition to just sharing what we were up to and what we were working on, we would also answer the question what's something new to us. And that was a space for people to share things that they learned or even just, like, new things that they tried, like food, or activities, or whatnot. And I really enjoyed it as a way to get to know the team, especially when I was new to that client project. And recently, someone on the team ended up creating a random question generator. So now the question for the daily sync rotates. And I've been having a lot of fun with that. Some of the ones that I like are, what made you laugh recently? What's currently playing on your Spotify or YouTube? No cheating. MINA: [laughs] STEPHANIE: And then, yesterday, we had what's for dinner? As the question. And I really liked that one because it actually prompted me to [chuckles] think about what I was going to do for dinner as opposed to waiting till 5:00 p.m. and then stressing because I'm already hungry but don't have a plan [chuckles] for how I'm going to feed myself yet. So it ended up being nice because I, you know, kind of was inspired by what other people mentioned about their dinner plans and got my stuff together. MINA: That's shocking to me because we had just come off of two weeks of traveling together. And the one thing I learned about you is that you plan two meals ahead, but maybe that is travel stuff. STEPHANIE: I think that is extremely correct. Because when you're traveling, you're really excited about all the different things that you want to eat wherever you are. And so, yeah, we were definitely...at least I was planning for us, like, two or three meals [laughs] in advance. MINA: [laughs] STEPHANIE: But, when I'm at home, it is much harder to, I don't know, like, be motivated. And it just becomes, like, a daily chore. [laughs] So it's not as exciting. MINA: I think I'm the same way. I just had a whole bunch of family in town. And I was definitely planning dinner before we had breakfast because I'm like, oh, now I have to be responsible for all of these people. STEPHANIE: Yeah. I just mentioned the questions because I've been really having fun with them, and I feel a lot more connected to the team. Like, I just get to know them more as people and the things they're interested in, and what they do in their free time. So, yeah, highly recommend adding a fun question to your daily syncs. MINA: Yeah, we started doing that on Mission Control at our team sync meetings recently, too, where the first person...we actually have an order generator that somebody on the team wrote where it takes everyone's first and last name and scramble them and then randomizes the order. So you kind of have to figure out where in the queue you are and who's coming up next after you. But the first person that goes in the queue every day has to think of an icebreaker question. STEPHANIE: That's kind of a lot of pressure [laughs] for a daily meeting, especially if you're having to unscramble names and then also come up with the icebreaker question. I personally would be very stressed [laughs] by that. But I also can see that it's...I also think it's very fun, especially for a small team like yours. MINA: Yeah, yeah, just seven of us; we get to know really well what letters are in everyone's names. But I was first today, and I didn't have an icebreaker question ready. So I ended up just passing. So that's also an option. STEPHANIE: That's fair. Maybe I'll link you to our random question generator, so you can find some inspiration. [laughs] MINA: Yeah, it's a ChatGPT situation. STEPHANIE: So you mentioned that you and I had just been traveling together for two weeks. And that's because Mina and I were at RubyKaigi in Matsumoto, Japan, earlier this May. And that's the topic of today's episode: Our Experience at RubyKaigi. And the really cool thing that I wanted to mention was that this was all possible because Mina and I were sponsored by WNB.rb, which is a global community of women and non-binary people working in Ruby. And I've mentioned this group on the show before, but I wanted to plug it again because I think that this was something really special that we got to do. WNB runs a lot of initiatives, like, meetups and panels supporting people to speak at conferences and book clubs. And, you know, just many different programming events for supporting women and non-binary Rubyists in their career growth. And they are recently beginning a new initiative to sponsor folks to attend conferences. And Mina, you and I were the first people to get to try this out and go to an international conference. So that was really awesome. It was something that I don't think I would have done without the support from WNB. MINA: And you almost didn't do. I think there was a lot of convincing [chuckles] that went on at the beginning to kind of get you to, like, actually consider coming with me. STEPHANIE: It's true. It's true. I think you had DMed me, and you were, like, so, like, RubyKaigi, like, eyeball emoji. [laughs] I was, I think, hesitant because this was my first international conference. And so there was just a lot of, like, unknowns and uncertainty for me. And I think that's going to be part of what we talk about today. But is there anything that you want to say about WNB and how you felt about being offered this opportunity? MINA: Yeah. When Emily and Jemma, the founders of WNB, approached us with this opportunity and this offer, I think I was...taken aback is not really quite the right words but, like, surprised and honored, really, I think it's a better word. Like, I was very honored that they thought of us and kind of took the initiative to come to us with this offer. So I'm really grateful for this opportunity because going to RubyKaigi, I think it's always something that was on my radar. But I never thought that...well, not never. I thought that I had to go as a speaker, which would have been, like, a three to five-year goal. [laughs] But to be able to go as an attendee with the support of the group and also of thoughtbot was really nice. STEPHANIE: Yeah, absolutely. That investment in our professional development was really meaningful to me. So, like you, I'm very grateful. And if any of our listeners are interested in donating to WNB.rb and contributing to the community's ability to send folks to conferences, you can do so at wnb-rb.dev/donate. Or, if you work for a company that might be interested in sponsoring, you can reach out to them at organizers@wnb-rb.dev. MINA: I highly recommend doing that. STEPHANIE: So, one of the questions I wanted to ask you about in terms of your RubyKaigi experience was, like, how it lined up with your expectations and if it was different or similar to what you were expecting. MINA: Yeah, I have always heard that when people talk about RubyKaigi as a conference and about its contents, the word that everyone uses to describe it is technical. I have already had sort of a little bit of that expectation going in. But I think my interpretation of the word technical didn't really line up with how actually technical it was. And so that was one thing that was different than what I had expected. STEPHANIE: Could you elaborate on what was surprising about the way that it was technical? MINA: Yeah. I think that when I hear technical talks and having been to some Ruby and Rails confs here in the States, when I hear about technical talks, it's a lot more content about people using the technology, how they use Ruby to do certain things, or how they use Rails to achieve certain goals in their day-to-day work or side projects. But it seems at RubyKaigi; it is a lot more about the language itself, how Ruby does certain things, or how interpreters implement Ruby, the language itself. So I think it's much more lower-level than what I was expecting. STEPHANIE: Yeah, I agree. I think you and I have gone to many of Ruby Central conferences in the U.S., like RubyConf and RailsConf. So that was kind of my comparison as well is that was, you know, the experience that I was more familiar with. And then, going into this conference, I was very surprised that the themes of the talks were, like you said, very focused on the language itself, especially performance, tooling, the history and future of Ruby, which I thought was pretty neat. Ruby turns 30, I think, this year. And one thing that I noticed a lot was folks talking about using Ruby to reflect on itself and the possibilities of utilizing those capabilities to improve our experience as developers using the language. MINA: Yeah. I think one of the things I was really fascinated by is...you had mentioned the performance. There were several talks about collecting how Ruby performs at certain levels. And I thought that that was quite interesting and things I had never thought about before, and I'm hoping to think about in the future. [laughs] STEPHANIE: Yeah. One talk that I went to was Understanding the Ruby Global VM Lock by Ivo Anjo. And that was something that, you know, I had an awareness of that Ruby has this GVL and certain...I had, like, a very hand-wavy understanding about how, like, concurrency worked with Ruby because it hasn't been something that I've really needed to know too deeply in my day-to-day work. Like, I feel a little bit grateful not to have run into an issue where I had to, you know, dive deep into it because it was causing problems. [laughs] But attending that talk was really cool because I liked that the speaker did give, like, an overview for folks who might be less familiar but then was able to get really deep in terms of, like, what he was doing workwise with improving his performance by being able to observe how the lock was being used in different threads and, like, where it might be able to be improved. And he shared some of his open-source projects that I'll link in the show notes. But, yeah, that was just something that I was vaguely aware of and haven't yet, like, needed to know a lot about, but, you know, got to understand more by going to this conference. And I don't think I would have gotten that content otherwise. MINA: Yeah, I agree. The talk that you are referencing is one of my favorite as well. I think, like you, kind of this vague idea of there's things going on under the hood in Ruby is always there, but to get a peek behind the curtain a little bit was very enlightening. I wrote down one of the things that he said about how highly optimized Ruby code can still be impacted and be slow if you don't optimize GVL. And he also shared, I think, some strategies for profiling that layer in your product, if that is something you need, which I thought was really cool. STEPHANIE: Yeah. I think I had mentioned performance was a really big theme. But I didn't realize how many levers there were to pull in terms of the way Ruby is implemented or the way that we are able to use Ruby that can improve performance. And it's really cool to see so many people being experts at all of those different components or aspects of making Ruby fast. [laughs] MINA: Yeah. I think that part of the work that we do on Mission Control is monitoring performance and latency for our clients. And while I don't expect having to utilize some of the tools that I learned at RubyKaigi, I expect being aware of these things helping, I think, in the long run. STEPHANIE: Yeah, absolutely. Joël and I have talked on the show about this idea of, like, push versus pull learning. So push, being you consume content that may not be relevant to you right now but maybe will be in the future. And you can remember, like, oh, I watched a talk on this, or I read something about this, and then you can go refer back to it. As opposed to pull being, like, I have this thing that I don't understand, but I need to know right now, so I'm going to seek out resources about it. And I think we kind of landed on that both are important. But at Kaigi, especially, this was very much more push for me where there's a lot of things that I now have an awareness of. But it's a little different, I think, from my experience at Ruby Central conferences where I will look at the schedule, and I will see talks that I'm like, oh, like, that sounds like it will be really relevant to something I'm working through on my client project or, like, some kind of challenging consulting situation. And so the other thing that I noticed that was different was that a lot of the U.S. conferences are more, I think like business and team challenges-focused. So the talks kind of incorporate both a technical and socio-cultural aspect of the problems that they were solving. And I usually really like that because I find them very relatable to my day-to-day work. And that was something that was less common at Kaigi. MINA: Also, that I've never been to a conference that is more on the academic side of things. So I don't know if maybe that is more aligned with what Kaigi feels like. STEPHANIE: Yeah, that's true. I think there were a lot of talks from Ruby Committers who were just sharing, like, what they've been working on, like, what they've been thinking about in terms of future features for Ruby. And it was very much at the end of those talks, like, I'm open to feedback. Like, look out for this coming soon, or, like, help contribute to this effort. And so it was interesting because it was less, like, here are some lessons learned or, like, here are some takeaways, or, like, here's how we did this. And more like, hey, I'm, you know, in the middle of figuring this out, and I'm sharing with you where I'm at right now. But I guess that's kind of the beauty of the open-source community is that you can put out a call for help and contributions. MINA: Yeah, I think they call that peer review in the academic circles. STEPHANIE: [laughs] That's fair. MINA: [laughs] STEPHANIE: Was there anything else that you really enjoyed about the conference? MINA: I think that one of my favorite parts, and we've talked about this a little bit before, is after hours on the second day, we were able to connect with Emori House and have dinner with their members. Emori House is a group that supports female Kaigi attendees specifically. I think it's that they, as a group, rent out an establishment or a house or something, and they all stay together kind of to look out for each other as they attend this very, I think, male-dominated conference. STEPHANIE: Yeah. I loved that dinner with folks from Emori House too. I think the really cool thing to me is that it's just community and action, you know, like, someone wanted to go to this conference and make it easier for other women to go to this conference and decided to get lodging together and do that work of community building. And that social aspect of conferences we hadn't really talked about yet, but it's something that I really enjoy. And it's, like, one of the main reasons that I go to conferences besides learning. MINA: Yeah, I agree. At the Ruby Central conferences, one of my favorite parts is always the hallway track, where you randomly meet other attendees or connect with attendees that you already knew. And like I mentioned, this dinner with Emori House happened on the second night. And I think by midday second day; I was missing that a little bit. The setup for RubyKaigi, I noticed, does not make meeting people and organizing social events as easy as I had been used to, and part of that, I'm sure, is the language barrier. But some places where I had met a lot of the people that I call conference friends for Ruby Central conferences had been at the lunch table. And Kaigi sets up in a way where they send you out with food vouchers for local restaurants, which I thought was really cool. But it doesn't make meeting people and organizing groups to go out together with people you don't already know a little more difficult. So meeting Emori House on the second night was kind of exactly what I had been missing at the moment. STEPHANIE: Yeah, agreed. I also really thrive off of more smaller group interactions like organically, you know, bumping into people on the hallway track, ideally. I also noticed that, at Kaigi, a lot of the sponsors end up hosting parties and meetups after the conference in the evenings. And so that was a very interesting social difference, I think, where the sponsors had a lot more engagement in that sense. You and I didn't end up going to any of those drink-ups, are what they're called. But I think, similarly, if I were alone, I would be a little intimidated to go by myself. And it's kind of one of those things where it's like, oh, if I know someone, then we can go together. But, yeah, I certainly was also missing a bit of a more organic interaction with others. Though, I did meet a few Rubyists from just other places in East Asia, like Taiwan and China. And it was really cool to be in a place where people are thinking about Ruby differently than in the U.S. I noticed in Japan; there's a lot more energy and enthusiasm about it. And, yeah, just folks who are really passionate about making Ruby a long-lasting language, something that, you know, people will continue to want to work with. And I thought that was very uplifting because it's kind of different from what the current industry in the U.S. is looking like in terms of programming languages for the jobs available. MINA: It's really energizing, I think, to hear people be so enthusiastic about Ruby, especially, like you said, when people ask me what I do here, I say, "Developer," and they say, "Oh, what language do you work in?" I always have to be kind of like, "Have you heard of Ruby?" [laughs] And I think it helps that Ruby originated in Japan. They probably feel a little bit, like, not necessarily protective of it, but, like, this is our own, and we have to embrace it and make sure that it is future-facing, and going places, and it doesn't get stale. STEPHANIE: Right. And I think that's really cool, especially to, you know, be around and, like, have conversations about, like you said, it's very energizing. MINA: Yeah, like you mentioned, we did meet several other Rubyists from, like, East Asian countries, which doesn't necessarily always happen when you attend U.S.-based or even European-based conferences. I think that it is just not as...they have to travel from way farther away. So I think it's really cool to hear about RubyConf Taiwan coming up from one of the Rubyists from Taiwan, which is awesome. And it makes me kind of want to go. [laughs] STEPHANIE: Yeah, I didn't know that that existed either. And just realizing that there are Rubyists all over the world who want to share the love of the language is really cool. And I am definitely going to keep a lookout for other opportunities. Now that I've checked off my first international conference, you know, I have a lot more confidence about [laughs] doing it again in the future, which actually kind of leads me to my next question is, do you have any advice for someone who wants to go to Kaigi or wants to go to an international conference? MINA: Yeah, I think I have both. For international conferences in general, I thought that getting a buddy to go with you is really nice. Steph and I were able to...like, you and I were able to kind of support each other in different ways because I think we're both stressed [laughs] about international travel in different ways. So where you are stressed, I'm able to support, and where I'm stressed, you're able to support. So it was really nice and well-rounded experience because of that. And for RubyKaigi specifically, I would recommend checking out some of the previous year's talks before you actually get there and take a look at the schedule when it comes out. Because, like we said, the idea of, I think, technical when people use that word to describe the content at RubyKaigi is different than what most people would expect. And kind of having an idea of what you're getting into by looking at previous videos, I think, will be really helpful and get you in the right mindset to absorb some of the information and knowledge. STEPHANIE: Yeah, absolutely. I was just thinking about...I saw in Ruby Weekly this week Justin Searls had posted a very thorough live blogging of his experience at Kaigi that was much more in the weeds of, like, all of the content of the talks. And also had tips for how to brew coffee at a convenience store in Japan too. So I recommend checking that out if folks are curious about...especially this year before the videos of the talks are out. I think one thing that I would do differently next time if I were to attend Kaigi or attend a conference that supports multiple languages...so there were talks in Japanese and English, and the ones in Japanese were live interpreted. And you and I had attended, like, one or two, but it ended up being a little tough to follow because the slides were a little bit out of sync with the interpretation. I definitely would want to try again and invest a little more into attending talks in Japanese because I do think the content is still even different from what we might be seeing in English. And now that I know that it takes a lot of mental energy, just kind of perhaps loading up on those talks in the morning while I'm still, you know -- MINA: [laughs] STEPHANIE: Fresh-faced and coffee-driven. [laughs] Rather than saving it for the afternoon when it might be a little harder to really focus. MINA: I think my mental energy has a very specific sweet spot because definitely, like, late in the afternoon would not be good for that. But also, like, very early in the morning would also not be very good for that because my coffee hasn't kicked in yet. STEPHANIE: That's very real as well. MINA: Do you think that there is anything that the conference could have done to have made your experience a little tiny bit better? Is there any support that you could have gotten from someone else, be it the conference, or WNB, or thoughtbot, or other people that you had gone with that could have enhanced this experience? STEPHANIE: Hmm, that's an interesting question. I'm not really sure because I was experiencing so many new things -- MINA: [laughs] STEPHANIE: That that was kind of, like, what was top of mind for me was just getting around even just, like, looking at all the little sponsor booths because that was, like, novel for me to see, like, different companies that I've never heard of before that I think when I asked you about expectations earlier, like, I actually came in with not a lot of expectations because I really was just open to whatever it was going to be. And now that I've experienced it once, I think that I have a little more of an idea of what works for me, what I like, what I don't like. And so I think it really comes down to it being quite a personal experience and how you like to attend conferences and so -- MINA: For sure. STEPHANIE: At the end of the day, yeah, like, definitely recommend just going if that opportunity is available to you and determining for yourself how you want that experience to be. MINA: Certainly. I think just by being there you learn a lot about what you like in conferences and how we like to attend conferences. On a personal level, I'm also an organizer with Ruby Central with their scholarship committee. And that's somewhere where we take new Rubyists or first-time conference attendees and kind of lower the barrier for them to attend these conferences. And the important part I wanted to get to is setting them up with a mentor, somebody who has attended one of these conferences before that can kind of help them set goals and navigate. And I thought that someone like that would...at RubyKaigi, being both our first times, might be useful. STEPHANIE: Yeah, absolutely. I think that's totally fair. One thing I do really like about the Ruby Central conferences is the social support. And I think you had mentioned that maybe that was the piece that was a little bit missing for you at this conference. MINA: Yeah. I know that someone had asked early on, I think, like, the night before the conference officially kicked off, whether there is a Slack or Discord space for all conference attendees so that people can organize outings or meals. And that is definitely something that at least the Ruby Central conferences have, and I imagine other conferences do too, that was missing at Kaigi as well. STEPHANIE: I'm wondering if you would go to Kaigi again and maybe be that mentor for someone else. MINA: I think so. I think I had different feelings about it when we were just leaving the conference, kind of feeling like some of these things that I'm learning here or that I'm being made aware of rather at RubyKaigi will come up important in the future, but maybe not right away. So then I was kind of walking away with a sense of, like, oh, maybe this is a conference that is important, but I might deprioritize if other opportunities come up. But then I started to kind of, like, jot down some reflections and retroing with myself on this experience. And I thought what you mentioned about this being the sort of, like, the push learning opportunity is really nice because I went in there not knowing what I don't know. And I think I came out of it at least being a little bit aware of lots of things that I don't know. STEPHANIE: Yeah, yeah. Maybe, like, what I've come away with this conversation is that there is value in conferences being different from each other, like having more options. And, you know, one conference can't really be everything for everyone. And so, for you and I to have had such a very different experience at this particular conference than we normally do, that has value. It also can be something that you end up deciding, like, you're not into, and then you know. So, yeah, I guess that is kind of what I wanted to say about this very new experience. MINA: Yeah, having new experiences, I think, is the important part. It's the same idea as you want to get a diverse group of people in the room together, and you come out with better ideas or better products or whatever because you have other points of view. And I think that attending conferences, even if not around the world, that are different from each other either in academia or just kind of, like, branching out of Ruby Central conferences, too, is a really valuable experience. Maybe conferences in other languages or language-agnostic conferences. STEPHANIE: Yeah, well said. On that note, shall we wrap up? MINA: Let's do it. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeeeee!!!!!!!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
If you're in the market for bicycle shorts, Joël's got you. Stephanie just returned from RubyKaigi in Japan and shares details of her trip. Recently at thoughtbot, there have been conversations around an interesting data modeling exercise. Joël and Stephanie discuss the following: Value Objects vs. Hashes Doing Math on Compound Numbers Monoids and Folding Naming Concepts in Code This episode is brought to you by Airbrake (https://airbrake.io/?utm_campaign=Q3_2022%3A%20Bike%20Shed%20Podcast%20Ad&utm_source=Bike%20Shed&utm_medium=website). Visit Frictionless error monitoring and performance insight for your app stack. Ruby Kaigi (https://rubykaigi.org/2023/) Google Translate Lens (https://lens.google/) Video on city parks (https://www.youtube.com/watch?v=qnyikrFlGdU) Enumerable#tally (https://ruby-doc.org/3.2.2/Enumerable.html#method-i-tally) Hash#merge (https://ruby-doc.org/3.2.2/Hash.html#method-i-merge) Monoids (https://blog.ploeh.dk/2017/10/06/monoids/) Enumerable#all? (https://ruby-doc.org/3.2.2/Enumerable.html#method-i-all-3F) Value of specialized vocabulary (https://www.bikeshed.fm/356) Gist with Joël's code solution (https://gist.github.com/JoelQ/3056a0a6e8b5488faa5caeef630cd702) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a little bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: I've made an unusual purchase this week. I went out and bought a pair of bicycle shorts. And, for those who are not aware, these are special shorts that have padding built into them. Typically, they're, like, skin-tight, but I got, I guess, what are called mountain biking shorts. So, they kind of look more like the cut of a normal short. But they've got this, like, built-in padding for biking. STEPHANIE: So. Just to confirm, you did get these shorts for biking purposes, right? JOËL: Yes. I purchased these shorts for biking purposes. STEPHANIE: Okay. [laughs] JOËL: And I got these because I was talking to a friend about this and mentioning that this was, like, probably the most ambitious cycling thing I've ever done in my life. And they recommended if you have not done bike shorts, you really should get them. They make a big difference. STEPHANIE: Wow. Okay, I have two thoughts here. First of all, you prefaced this saying that this was an unusual purchase. So I thought maybe that you bought these bike shorts for some other purpose. [laughs] But I am excited to talk about this because I've also been curious about trying bike shorts. I bike a lot in Chicago in the summer, and I've been doing, like, longer rides on the Lakefront trail. And one of my goals, actually, this summer is to do a bikepacking trip. But I have not been super comfortable on longer rides. And I was just thinking that this might be something really helpful to make them a little more enjoyable. JOËL: So, is the kind of biking that you're doing closer to what might be considered commuting? STEPHANIE: Yeah, mostly commuting. But also, just, like, going on long rides on the weekends, in addition to this, hopefully, forthcoming bikepacking trip up to a state park. So not too long, maybe, like, 60 miles, but definitely long enough to start getting a little uncomfy on your seat. JOËL: Yeah, is 60 miles, like, in one day? STEPHANIE: Yeah, exactly. JOËL: That's a lot. Yeah, the friend who recommended biking shorts to me told me that pretty much anything over maybe 10 miles is worth getting shorts. STEPHANIE: Wow, okay. I clearly have been suffering [laughs] for way too long, then. Tell me more about your cycling trip. JOËL: So this is a bikes plus beer trip. Basically, I plotted a bunch of breweries in Belgium on a map and constructed an itinerary that could hit a bunch of them while keeping fairly short rides between towns. And the goal is to do maybe 30-35 miles in a day. And so I'll be going probably, like, cycling in the morning, and then exploring and drinking in the afternoon and evening. STEPHANIE: That sounds amazing. That's really cool to do a little bit of a tour of the area and then also traveling by bike. JOËL: Yeah, I'm excited because other modes of transport really just give you the origin and the destination, whereas cycling, you kind of get all of the in-between places. You get a much better feel for the area that you're in. And you can make all these unexpected stops if you want. You can make detours. So I feel like you get the sort of being in the moment, being in the place effect that you would have as a pedestrian but with a much longer reign. STEPHANIE: Yeah, absolutely. That's exactly what I was going to say. I love cycling. And there's something really special about being able to be present in your surroundings and seeing people on the street or a cool building as you're going. But also going at a speed where it feels very fun and very freeing to just be cycling through a town and making stops when you want to, and traveling greater distances than you could be able to on foot. JOËL: So I just received these bike shorts yesterday in the mail. So today, at the end of the day, I'm going out for a bike ride, and I'm going to see if they perform as advertised. STEPHANIE: That's exciting. Keep us posted [laughs] on if you end up liking them or not. JOËL: Yeah, yeah. The next episode or two, I'll have to report bike shorts; yay or nay? STEPHANIE: Yeah, The Bike Shed will now become bike gear reviews. JOËL: The name will actually line up, then with what the people googling, it might think it actually is. Stephanie, what's new in your world? STEPHANIE: Speaking of vacation, I just got back from a two-and-a-half-week trip myself. I mentioned on the podcast a couple of episodes ago, I think, that I was traveling to Japan for RubyKaigi, an international Ruby Conference over in Japan. And then I spent another week in Taiwan, just on my own time. So, yeah, I had a really big, long trip, and it was really great. It was my first time going abroad in a really long time. It was my first time being somewhere where I didn't speak the language. So, in Japan...I don't speak any Japanese. And it was both challenging and also, like, not too bad. I found my way around through a lot of gesturing and smiling, and nodding. [laughs] And, hopefully, people were able to understand what I was trying to communicate. Also, pointing at menus, I highly recommend going to places that have pictures of the food, and then you can just point when you want to order. [laughs] JOËL: So, did you find that English was not particularly useful then in Japan as a tourist? STEPHANIE: Yeah, I would say so. The next thing was that most signs were translated. So we ended up taking public transportation a lot. And that was quite easy to navigate, especially since I have kind of navigated subways in other cities before, and reading the signs is no problem. But when you're trying to communicate with locals, that was a little harder. JOËL: Did you use any, like, apps on your phone or anything like that to help navigate kind of the different language? STEPHANIE: Yeah, the Google Translate Lens app. I can't remember exactly what it is. But this was my first time really using it. And I was really impressed by how it was able to translate things that you're using your camera to take pictures of, or just, like, having your camera view. I did feel a little silly, like, holding my phone up to everything and trying [laughs]...so I could understand what I was reading. But for menus that did not have pictures, that was my backup strategy. [laughs] JOËL: Did you ever have to have your phone translate something and then just show your phone to someone else? STEPHANIE: No, I didn't have to go that far. Though I do think that it has a feature where you can have someone speak into the phone, and it will translate that into your native language. And then you respond by speaking into it and then playing the sound for them, which, you know, I bet really works in a pinch. But I think that required a little more investment into the interaction [laughs] with the other person than I was ready for. Like I said, the gesturing served me quite well. JOËL: I got the experience of being on the other side of that a while back. So, here in Boston, I was just walking down the street, and someone stopped me and just holds up their phone. And they've typed something in Chinese on there. And they hit a button, and it comes in English. STEPHANIE: [laughs] JOËL: And they're asking for directions. And I think I typed a sentence back on their phone in English, and then they hit the translate button and got it back in Chinese. We went back and forth a few times. And eventually, I think he got what he wanted, and we went our separate ways. And I was kind of amazed that this whole interaction happened. STEPHANIE: Yeah, that's really cool. JOËL: Yeah, kudos to that person for having the courage to stop someone on the street when you don't speak their language. STEPHANIE: Yeah, absolutely. I think even when I was struggling to communicate with someone because of the language barrier, I could tell from their gesturing in return that we were, like, willing to help each other out. And that, like, there was still an ability to find some kind of connection, even though, you know, we didn't completely understand each other. And that was definitely one thing that I really enjoyed was being in a place with, you know, people different from me and having that exposure. It's been a really long time since I've got to experience that, and that was really valuable. JOËL: So, other than the conference, what would you say are some highlights of the trip for you, maybe one from Japan and one from Taiwan? STEPHANIE: So one of my favorite things about being in Tokyo was all the green space that was around. I ended up walking a lot just to explore the neighborhoods. And I always just stumbled across a local park or even a shrine that had really great nature around it, a lot of big trees. You know, some, like, water features, maybe like a pond, and a lot of really fun plants that I got to learn about. And, yeah, that was really nice, especially in such a dense urban area, like, coming across green space to just sit for a little while. And it was such a nice relief from the density and busyness of a big city. That was just one thing that I was really impressed by being in Japan. JOËL: That's really cool. I think that really speaks to the quality of their urban planning. I know that the stereotype of Tokyo that I have in my mind is that it's, like, you know, ultra-modern, ultra-urban, you know, it's the largest city in the world. So the idea that they've taken the time to set up all these little parks everywhere is really endearing. Particularly, I think the idea of smaller parks at the neighborhood level where you don't need, you know, something massive like, let's say, New York's Central Park, which is, you know, really cool. But having just a little green space in your neighborhood where you can, like, stop by, I think it's a wonderful upgrade to local people's quality of life. I was recently listening to a video on YouTube from a city planning channel talking about just all the thinking that goes behind city parks, and having them at different scales, and how that impacts the residents of different areas. So it's really cool to hear that Tokyo has done a great job with that. STEPHANIE: Yeah, absolutely. I think part of the joy of just stumbling upon it was that you know, even when I wasn't seeking it out, it would just come along during my walks. And, yeah, it really was very refreshing. JOËL: What about Taiwan? STEPHANIE: So, in Taiwan, what I really enjoyed about it it's a bit of a smaller island. And so you can actually get to a lot of places within a few days. And a lot of folks take day trips out to the coast from Taipei. And I was able to do a two-day trip to another county that had some hot springs, and I got to enjoy an outdoor hot springs in the rain. And that was really nice because it was, like, surrounded by trees. And it happened to be raining that morning, but, you know, we were all kind of already getting wet, so it didn't really matter. And it was just, like, this really serene and gorgeous experience being able to enjoy that. And I think that was another place where I was in a very urban area, and then being able to escape a little bit was really nice. JOËL: That sounds like a magical moment. Have you visited hot springs before, or was this your first time going to a hot spring? STEPHANIE: I have been to a few in the U.S. before. I like to take road trips to national parks. And there are some really great hot springs in the U.S. as well. And so this was kind of something that I really wanted to do somewhere else just to experience it elsewhere. And, yeah, I'm really glad to have checked that off my bucket list. JOËL: That's really cool. I've never been to a hot spring, and it sounds like a fun thing to do. So it's on my kind of greater bucket list. It's maybe not a top-five thing to do, but definitely, something I want to do one day. STEPHANIE: Cool. Love it. That was vacation talk from Joël and Stephanie. [laughs] MID-ROLL AD: Debugging errors can be a developer's worst nightmare...but it doesn't have to be. Airbrake is an award-winning error monitoring, performance, and deployment tracking tool created by developers for developers that can actually help cut your debugging time in half. So why do developers love Airbrake? It has all of the information that web developers need to monitor their application - including error management, performance insights, and deploy tracking! Airbrake's debugging tool catches all of your project errors, intelligently groups them, and points you to the issue in the code so you can quickly fix the bug before customers are impacted. In addition to stellar error monitoring, Airbrake's lightweight APM helps developers to track the performance and availability of their application through metrics like HTTP requests, response times, error occurrences, and user satisfaction. Finally, Airbrake Deploy Tracking helps developers track trends, fix bad deploys, and improve code quality. Since 2008, Airbrake has been a staple in the Ruby community and has grown to cover all major programming languages. Airbrake seamlessly integrates with your favorite apps to include modern features like single sign-on and SDK-based installation. From testing to production, Airbrake notifiers have your back. Your time is valuable, so why waste it combing through logs, waiting for user reports, or retrofitting other tools to monitor your application? You literally have nothing to lose. Head on over to airbrake.io/try/bikeshed to create your FREE developer account today! JOËL: So recently at thoughtbot, we've been having conversations around this really interesting data modeling exercise, where let's say this is a company, and you want to purchase T-shirts for everyone at the company. You have already some T-shirts on hand because you've done this kind of thing before in a couple of different warehouses. And you need to know how many new T-shirts you need to order in order to have enough for everyone. So as long as you keep things simple, the math is pretty easy because you sum the number of people at your company, and then you sum the number of shirts across all of your warehouses, and that gives you the T-shirts that you need, the T-shirts that you have. You get the difference between those two numbers, and that tells you how many new T-shirts you need to order. Where things get more complicated is once you start introducing T-shirt sizes, and that's where the fun data modeling comes in. If everyone at your company has a T-shirt size that they want and then at your warehouses, you store...the object that represents a warehouse stores a hash of sizes and how many of each size you have. Now, how do you do all this, like, summing across things? And it's not really just a single number that you want. Now you need to know how many small, mediums, and larges. And, sometimes, you've got a hash. Sometimes you've got just symbols on a user, and you've got a sum across hashes. Maybe do some differences across hashes. And it gets kind of tricky to work with. So that's sort of the problem as it's initially presented. And we've been having a really interesting conversation around different ways to try to solve it in a way that's really kind of clean and nice. STEPHANIE: Yeah, that's interesting because what you described sounds like the first iteration of solving the problem is, oh, the warehouse stores this information as a hash. So maybe I will create a new hash for the counts of T-shirt sizes that I need and then do the comparison on those two hashes. It sounds like maybe there was some unwieldiness or maybe even some duplicated code there. Is that what you think you all were trying to solve by modeling this differently? JOËL: I think we kind of quickly hit some limitations with hashes. One thing that is fun before we start trying to combine a bunch of hashes is that some of the data exists as a hash on the warehouses. But to get the T-shirts that we need, all we have are an array of users and a size on all of them. And we can use this fun method from Enumerable called Tally to give us a kind of Tally hash that is just a mapping of size, two counts of that size in the array. And so that's a really fun method. You don't get to bring it out that often in Ruby. And it's nice because that hash format happens to match the same format as the hashes stored on the warehouse objects. STEPHANIE: Right. So now you're comparing apples to apples. But it sounds like maybe this hash representation does hold some kind of significance. JOËL: Yeah. I guess, for me, I tend to see anytime you're doing fancier operations on a hash more than just reading in and out; it probably wants to be some kind of value object. And, in this case, we kind of want to do math on hashes. I think the equation is kind of still the same thing. We're trying to get the difference between the two, between the want versus have, but you can't just subtract one hash from another directly. There's some things that you can do with the hash merge method that allows you to pass a custom block and do some things there. But we're going to have to do this sort of repeatedly. And now we're kind of leaking some of that knowledge a little bit. So it feels like something where you might want to actually name this concept and make it an object of its own that can then have its own kinds of domain operations as methods on it. STEPHANIE: Yeah, I like that a lot. Because even just as I was thinking about it when you are storing data like that in just a hash, what do you call it? Like, what do you name it? I think I've seen things like that named, like, T-shirt data, or, like, warehouse data, or warehouse T-shirt counts, or T-shirt counts. You know, that is when it starts to diverge, and you end up maybe seeing the same, like, data represented, but it being named different things in different parts of the code. And I, in experience, have found that very painful. JOËL: Yeah, because I guess you could have, like, T-shirts on hand from your warehouse; that's one hash. But the hash generated from the users might get called something like user preferences. And if you're reading through that code and you see a hash, and you're like, okay, do these two hashes that I'm looking at, maybe in a test, just kind of coincidentally have the same keys? Or are these kind of fundamentally the same thing? Or is the idea of, like, T-shirts on hand like a stock different from, like, a preference? And do they represent different things that just happen to be similar in this particular scenario? STEPHANIE: Right. And especially if then there are methods where you're passing that data structure that really represents the same thing. But you're passing it as arguments, and then, suddenly, one variable name, user preferences, or user T-shirt preferences becomes, you know, T-shirt count. That has been really confusing for me before. JOËL: One thing that does get, I think, clunky very quickly is that you have all of these warehouse objects that have that hash of, like, stock on hand on them. And what you really want is a kind of aggregate object that tells you not what's the stock on hand for one warehouse but across all warehouses. So you've got to go through, I guess, that array of warehouses and somehow kind of aggregate all of those hashes together. And because they're already tallies, you can't just do Enumerable Tally on it anymore. You've got to find some way to combine them together, and that gets tricky really quickly. STEPHANIE: Right. I can see they're starting to be, like, nested loops, especially if you're just working with primitives. JOËL: I think some initial implementations that we saw ended up doing either, like, some kind of reduce block or eachwithobject, or something like that, which are, I think, fine solutions here. But what lives inside of those blocks is what gets complicated. And I don't know about you, but I feel like if I'm reading through some code and then all of a sudden I see a reduce block, and it's, like, ten lines of logic with maybe some, like, nested things, like, maybe some nested loops or some conditions inside of it, that's kind of intimidating. Reduce is not a super easy method to wrap your head around, especially when the block has got a lot of logic. STEPHANIE: Yeah, that's a really good point. It definitely gives me pause. And I have to, like, you know, commit to reading the method in its entirety to fully understand [laughs] what's going on. JOËL: Sometimes, like, really pause and, like, annotate with comments and all this stuff. STEPHANIE: So, what did you end up thinking about in terms of solving that problem of aggregating the sums of all the different T-shirt sizes for each warehouse? JOËL: So I think, for me, oftentimes, it's easier to make the problem a little bit smaller, solve that smaller problem, and then try to kind of scale up back up again and particularly when you're dealing with something like reducing or aggregating a large collection. Like, forget about dealing with a collection. Just how could I combine two items of this type? So if I had two of these hashes. And forget about fitting it for an array. But if I have two of these hashes, how could I combine them together? And you could do this with hash merge. I wanted to do things a little bit more encapsulated. And because I also knew that we're building some more logic around these, I actually wrote a custom object. I called it a tally, maybe inspired by that Enumerable method, and implemented an operator plus on this tally object. So a tally object can plus another tally object. And the response from that is you get a third tally object that's gone through all of the keys and summed them together. So it's kind of an aggregate sum. STEPHANIE: This is a cool example of a method that's a verb also representing a noun to name the return value, right? So the Tally method on Enumerable returns a hash, which we have been talking about for a while as, like, a data structure that's, you know, perfectly fine, but maybe we can leverage turning it into like you said, a value object to give it more meaning or to make it easier to work with. And it seems like the naming part just kind of fell into your lap. JOËL: Yeah, tally is interesting in that it is both a noun and a verb in English. I'm not sure what the grammatical term for that kind of word is. STEPHANIE: So, once you extracted this new class out, what insights or observations did you have about this problem? JOËL: What becomes really cool about this is that once you have a way of combining two objects together, reduce is a way to just kind of scale that up to an arbitrary number. And so, just like you can sum an array of numbers by reducing plus over the array. Because I have plus on my tally object, I can reduce plus operator over an array of tally objects. And they all just kind of sum together in a single tally that's the combination of all of them. So this is really cool. What used to be an intimidating reduce block, the intimidating logic gets moved into a plus method, which I think is much more approachable. Because I can go in the context of an object and say, okay, I've got this tally object, and I'm trying to add it to another tally object. And we're just going one key at a time, adding them together. Simple enough. And then in the place where we're reducing, all we're saying is list of tallies reduce plus. And I know that pattern already because I do it with integers to sum them together. And so now I've just got this really simple one-line in the scary part. And the actual complex logic is much more approachable. STEPHANIE: That is very cool. I found it really interesting that this came about because we were trying to do math on these two hashes. So it seems like, you know, a tally because it represents a score or, like, a number. Like, we were able to implement those plus operators and get to a simple solution because we're working with numbers. JOËL: Yeah, I think it might be fair to describe it as maybe a compound number is the term that I use. I don't know if that's mathematically correct. Oftentimes, when you're dealing with things that represent a number or something that's represented numerically but that might have more than one number involved in it. But you still want to do math with this kind of compound, multi-number value anyway. And one example that you might have is, let's say, a point in 2D space. You have an X coordinate and a Y coordinate. And you can do math on points. In fact, there's a whole field of math to deal with that kind of thing. That's an important thing that you have to do. You might want to be able to add or subtract points. You might want to do certain types of multiplication on them. And so just because something has more than one number associated to it doesn't mean that it can't be used for math. In fact, oftentimes, that's where the fancier math does come into play. But when we treat them as primitives, and we just have, let's say, our XY pair was a hash, or, like, a two-element array, then we lose the ability to do math nicely. If we create, let's say, a point class that has an X and Y, and then we define plus, we define minus, we define scalar and vector multiplication, things like that, now we can do all those operations. And we can treat it like math, even though it's not just a simple integer anymore. STEPHANIE: Yeah, I like that a lot because we do end up working with data, you know, maybe even from our database. But then, inevitably, we want to, like, learn something about it. And so I was thinking about how frequently I use GROUP BY in MySQL queries and how, oftentimes, I care about counts, or, like, number of records. And perhaps this is why we see, like, the hash primitive used so frequently in codebases that then become pretty complicated once we're trying to, like I mentioned, like, learn something about it or, like, compare things or whatever logic that we need to do. And transforming them into objects that then know how to do math on themselves [laughs] is very cool. JOËL: Hashes are interesting because they're pretty much just basic data structures. And I think, very often, they're sort of pre-objects. They're things that want to eventually become objects. And, oftentimes, what I find is that hashes get passed around a system. And various other classes or subsystems all have bits of logic that act on the hash because the hash can't own that. And so you end up with the logic around the concept of whatever the hash represents kind of scattered and maybe duplicated across three or four places in the application. And then, all of a sudden, if you give that a name, if you create a class for it, you can pull all of that logic into one place. And, all of a sudden, it probably cleans up all of the surrounding places because now they don't have to care about the implementation of exactly what operating on the hash is. But, also, it means that these operations generally have, like, nice domain names. And, in the case of a complex number, you might even have that represented through math operations, like, plus or minus. And that allows your code to read really nicely. STEPHANIE: Right. Which gets me thinking about how I mentioned, like, tally as a noun, and, you know, you implemented your custom class. But do you think there's any value in the idea of a tally being specifically like a hash-like thing with a number as the value for each key, like, that existing as a more general class for people to use? JOËL: Oh, that's interesting. So, in my personal implementation, I hard-coded values for small, medium, and large because those were the T-shirt sizes from the example. But you're talking about some sort of generic tally object that maybe would be a gem or something like that that people could use that represents counts of arbitrary things or multiple counts of arbitrary things that might then implement some common math operators so that you could add or subtract them. STEPHANIE: Yeah, exactly. Because I was just thinking, you know, like I mentioned, I often represent that when I count number of records in my database. Or even I can recall a problem that I encountered previously where I had to figure out the number of orders for an e-commerce store based on the location. And I held that in a hash data structure, but really, it's a tally. [laughs] And so, yeah, I think that maybe we've kind of stumbled across a very useful representation of very common problems. JOËL: Yeah, I can see there being use for a generic version of this. Maybe that's your chance to go out and create some open source, or maybe this already exists. We should maybe research that first. STEPHANIE: Yeah, if any one of our listeners know, [laughs] send us an email. JOËL: So something that was really interesting to me about all of these changes, introducing the value object, cleaning up the reduce, all that stuff, is that, in the end, once the...there was this object that represented the sort of aggregate compound value, the tally, then the equation stayed the same. And I can just slot in those variables as before. Whereas previously, when we switch from just a single count to this, like, we need to take into account sizes that, like, broke the initial implementation of the code. So it's funny how you sort of go from a simple implementation and then a new requirement, which breaks it. But then just changing the hash to be an object all of a sudden made the original code, which didn't really need to change; it just worked again. STEPHANIE: Hmm. That's really interesting because it makes me think about how maybe the primitives were perfectly fine, you know, in the first set of requirements, and not until, like, an additional complexity or something new emerged that we needed to reach for an object that could support the change. JOËL: Yeah. And I think I'd argue that if you're doing just raw T-shirt count, an integer is probably the right value to use there. But if you're doing counts broken out by T-shirt size, then having an object that's a single thing that responds to plus and minus so that you can use it in the same equation where you're saying sum up all of these things from the warehouse, and then do a difference with the T-shirts that we need that becomes really nice. STEPHANIE: Do you think there was some value in going through the hash implementation first, though, and then arriving at using a more custom object? I'm curious, kind of, like, what that journey was like. JOËL: It's hard to say. I would say maybe yes. But I could also see someone who's done this a lot, who's built the sort of heuristics, the instincts around this could immediately be like, oh, wait, we're trying to sum hashes here. Clearly, these need to be objects. Clearly, what we need is something that implements a plus operator that we can reduce. STEPHANIE: Yeah, I like that a lot. Because part of, you know, knowing what to reach for is having seen it enough times and seeing patterns, right? JOËL: This reminds me of a particular pattern that comes from the world of functional programming. It has a kind of scary-sounding name. It's monoid, not monad, monoid. And the idea in the context of Ruby is it's some kind of object that implements a plus method. So two of these objects can combine each other. And typically, you also have some sort of empty version of this object or some sort of, like, zero value. And there's a few rules that go around, like, kind of how this object has to behave. Like, you can't just put any implementation you want in that plus method. Certain requirements that have to be met for it to be considered, like, a valid plus method in this pattern. But if you do meet those requirements, then arrays of this type of object are just inherently reducible because you can just reduce plus over them. And so I think anytime you're trying to aggregate some sort of unwieldy data structure, that's probably a useful pattern to have because, you know, wait, as long as I have a way to combine two items together and potentially some way to generate an empty state, I can aggregate this whole list. STEPHANIE: I'm curious, does that also apply to non-numerical values? JOËL: Yes, any kind of aggregation combination, whatever. So maybe what you're doing is you're combining strings together. STEPHANIE: Got it. JOËL: String concatenation is a form of combination. And so you could be reducing some kind of concatenation over an array of strings, and you end up with one aggregate string that's the combination of all of them. Sometimes, though, you're not just taking values and putting them next to each other so that what you have is kind of all of them at the same time. You might instead do some kind of comparison. An example here might be Boolean values. You might say the way that I'm sort of, quote, unquote, "aggregating" two values, two Boolean values is with the operator AND. And so you have two Boolean values, and you get a new sort of combo value out of them, that is, are both of these values true? STEPHANIE: Whoa, that's blowing my mind right now. Because I had never thought of the, like, AND operator on Booleans, essentially aggregating them into a single true or false value. [laughs] JOËL: It's kind of weird, right? But I guess we do the same thing with numbers. One plus one doesn't give us 11 unless you're writing JavaScript. STEPHANIE: [laughs] JOËL: You know, we get a new number too, that is some sort of, like, combination of the two. So, similarly, it kind of makes sense that two Booleans might combine to create a new sort of third Boolean value. Where it gets really interesting, though, is that once you have this sort of combination, if you try to reduce AND over an array of Booleans, what you effectively have created is Ruby's Enumerable all method that checks to say, are all values in this array true? STEPHANIE: Interesting. But really, the way that's implemented is just, like, a definition of what aggregate means for Booleans, right? JOËL: Right. But it's taking that idea of aggregating two values and scaling it up to an array of many values. So we know Boolean AND. Another way to think about it is, are both of these values true? Is the question it's trying to answer. And then we're scaling that out to say, is both of these values true for everything? So are all of these values true? Because we're going from two to many. STEPHANIE: Cool. So maybe the takeaway for some of our listeners could be, like, next time they find themselves having to deal with a collection or an Enumerable and, you know, using a reduce or, like, trying to break it down to compare two of those elements first, and figuring out how they want that interaction to work. Does that sound right? JOËL: Yeah, absolutely. Once you have a way to combine two elements together, if you want to scale it up to n elements, you just plug it into reduce, and it does the rest of the work for you. My big takeaways from this exercise were one: the value of creating custom objects. Wrapping primitives like hashes in an object and adding a few domain methods on them made such a difference in my final implementation. Secondly, I think it's what you're saying, this whole thing about breaking down complex reduce problems by figuring out how to combine two items and then just using reduce to scale it to an array. And then, finally, I think this is a point that we've mentioned on this podcast before, the value of specific vocabulary - being able to name things and patterns. And so knowing some of the details of this monoid pattern and having a name for it means that now I start seeing it in places. And so the moment I see, oh, wait, we're aggregating values; we're combining two values together and then doing this in a reduce, immediately, my mind goes, wait, that feels like monoid. And then, I can explore that with my custom object to try to make the code better. STEPHANIE: Yeah. And even if you don't remember the monoid part specifically, the idea of Tally, like, that is something that I think is really cool and really applicable to a lot of codebases. JOËL: So, for those who are interested in more practically what this code looks like, I've put this all in a Gist, and I'll link to it in the show notes. This was a really fun exercise for me because I used sort of two development techniques to help sort of build this out. One, I went with a kind of literate programming approach, where I had just a Ruby file and would have put in some big comment blocks talking about what the setup was, what I was trying to do, and then describing how I'd like to use the code, and then try to write code that made that happen. And then, for the actual objects that I was using under the hood, I used TDD to test drive and build them out. So you've got all of that in the Gist. We've got the tests and that sort of literate programming script that almost reads like a mini blog post, except it's executable Ruby. So, if you're curious to see about that, the link is in the show notes. STEPHANIE: That's a very cool format. I'm excited to take a look. On that note, shall we wrap up? JOËL: Let's wrap up. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeee!!!!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
Joël gives a recap after attending RailsConf 2023 in Atlanta, Georgia (and yes, there was karaoke!
Engineering manager at Vox Media and author Nicole Zhu joins Stephanie on today's episode to discuss her writing practice. nicoledonut is a biweekly newsletter about the writing process and sustaining a creative life that features creative resources, occasional interviews with creative folks, short essays on writing and creativity, farm-to-table memes and TikToks, and features on what Nicole is currently writing, reading, and watching. This episode is brought to you by Airbrake (https://airbrake.io/?utm_campaign=Q3_2022%3A%20Bike%20Shed%20Podcast%20Ad&utm_source=Bike%20Shed&utm_medium=website). Visit Frictionless error monitoring and performance insight for your app stack. Kieran Culkin on learning about billionaires filming Succession (https://www.tiktok.com/@esquire/video/7215641441597410603?_r=1&_t=8bPK4Ingkf5) The Home Depot skeleton (https://twitter.com/jenni_tabler/status/1566266554240888832) Nicole Zhu's newsletter (https://nicoledonut.com/) The Making of a Manager by Julie Zhuo (https://www.juliezhuo.com/book/manager.html) Saving Time by Jenny Odell (https://www.penguinrandomhouse.com/books/672377/saving-time-by-jenny-odell/) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. And today, I'm joined by my friend and special guest, Nicole Zhu. NICOLE: Hi, I'm so excited to be here. My name is Nicole, and I am an Engineering manager at Vox Media and a writer. STEPHANIE: Amazing, I'm so thrilled to have you here. So, Nicole, we usually kick off the show by sharing a little bit about what's new in our world. And I can take us away and let you know about my very exciting weekend activities of taking down our Halloween skeleton. And yes, I know that it's April, but I feel like I've been seeing the 12-foot Home Depot skeletons everywhere. And it's becoming a thing for people to leave up just their Halloween decorations and, just as the other holidays keep rolling on, changing it up so that their skeleton is wearing like bunny ears for Easter or a leprechaun hat for St. Patrick's Day. And we've been definitely on the weird skeleton in front of the house long past the Halloween train for a few years now. Our skeleton's name is Gary. And it's funny because he's like a science classroom skeleton, so not just plastic. He's actually quite heavy. NICOLE: He's got some meat to the bones. [laughs] STEPHANIE: Yeah, yeah, and physiologically correct. But we like to keep him out till spring because we got to put him away at some point so that people are excited again when he comes back out in October. And the kids on our block really love him. And yeah, that's what I did this weekend. [laughs] NICOLE: I love it. I would love to meet Gary one day. Sounds very exciting. [laughs] I do get why you'd want to dress up the skeleton, especially if it's 12 feet tall because it's a lot of work to put up and take down for just one month, but that's fascinating. For me, something new in my world is the return of "Succession," the TV show. STEPHANIE: Oh yes. NICOLE: I did not watch yesterday's episode, so I'm already spoiled, but that's okay. But I've been getting a lot of Succession TikToks, and I've been learning a lot about the making of the show and the lives of the uber-rich. And in this one interview with Kieran Culkin, the interviewer asked him, "What's something that you learned in shooting the show about the uber-rich about billionaires that's maybe weird or unexpected?" And Kieran Culkin says that the uber-rich don't have coats because they're just shuttled everywhere in private jets and cars. They're not running to the grocery store, taking the subway, so they don't really wear coats, which I thought was fascinating. It makes a lot of sense. And then there was this really interesting clip too that was talking about the cinematography of the show. And what is really interesting about it is that it resists the wealth porn kind of lens because it's filmed in this mockumentary style that doesn't linger or have sweeping gestures of how majestic these beautiful cities and buildings and apartments they're in. Everything just seems very matter of fact because that is just the backdrop to their lives, which I think is so interesting how, yeah, I don't know, where I was like, I didn't ever really notice it. And now I can't stop seeing it when I watch the show where it's about miserable, rich people. And so I like that the visual language of the show reflects it too. STEPHANIE: Wow, yeah, that makes a lot of sense. The coat thing really gets me because I'm just imagining if I could be perfectly climate controlled all the time. [laughs] NICOLE: Right? Oh my gosh, especially you're based in Chicago [laughs], that is when you can retire the winter coat. That is always an important phase. STEPHANIE: Yeah, seriously. I also am thinking now about just like the montages of showing a place, just movies or shows filmed in New York City or whatever, and it's such...so you know it's like the big city, right? NICOLE: Mmm-hmm, mm-hmm. STEPHANIE: And all of that setup. And it's really interesting to hear that stylistically, that is also different for a show like this where they're trying to convey a certain message. NICOLE: Yeah, yeah, definitely. STEPHANIE: So I'm really excited to have you on The Bike Shed because I have known you for a few years. And you write this really amazing newsletter called "nicoledonut" about your writing practice. And it's a newsletter that I open every other week when you send out a dispatch. And last year at RubyConf, they had a conference track called Bringing Your Backgrounds With You. And there were talks that people gave about how the hobbies that they did outside of work or an identity that they held made them a better developer, like, affected how they showed up at work in a positive way. And as someone who has always been really impressed by the thoughtfulness that you apply to your writing practice, I was really curious about how that shows up for you as an engineering manager. NICOLE: Definitely a great question. And to provide a bit of context for listeners, I feel like I have to explain the newsletter title because it's odd. But there's a writer who I really love named Jenny Zhang, and her handle across the Internet is jennybagel. And so I was like, oh, that would be so funny. I should be nicoledonut. I do love donuts. My Neopets username was donutfiend, so it was -- STEPHANIE: Hell yeah. NICOLE: But anyway, so that was kind of...I was like, I need to come up with some fun title for this newsletter, and that is what I settled on. But yes, I've written personal essays and creative nonfiction. And my primary focus more recently these past few years has been fiction. And this newsletter was really kind of born out of a desire to learn in the open, provide resources, act as kind of a journal, and just process ideas about writing and what it means to kind of sustain a creative life. So it has definitely made me more reflective and proactively, like you said, kind of think about what that means in terms of how that transfers into my day job in engineering. I recently moved into management a little over a year ago, and before that, I was a senior full-stack engineer working on a lot of our audience experiences and websites and, previously, more of our editorial tools. So I think when it comes to obviously writing code and being more of an individual contributor, I think you had previously kind of touched on what does it mean to treat code as a craft? And I do think that there are a lot of similarities between those two things because I think there's creativity in engineering, of course. You have to think about going from something abstract to something concrete. In engineering, you're given generally, or you're defining kind of requirements and features and functionality. You may be make an engineering plan or something like that, an EDD, given those constraints. And then I think writing is very similar. You outline, and then you have to actually write the thing and then revise. I do think writing is not necessarily as collaborative as coding is, perhaps, but still similar overall in terms of an author having a vision, dealing with different constraints, if that's word count, if it's form or structure, if it's point of view, things like that. And that all determines what the outcome will be. You always learn something in the execution, the idea that planning can only take you so far. And at a certain point, you gather as much background knowledge and information and talk to as many people. Depending on the kinds of writing I do, I have or haven't done as much research. But at a certain point, the research becomes procrastination, and I know I need to actually just start writing. And similarly, with engineering, I think that's the piece is that once you actually start implementation, you start to uncover roadblocks. You uncover questions or complications or things like that. And so I think that's always the exciting part is you can't really always know the road ahead of you until you start the journey. And I also think that in order to benefit from mentorship and feedback...we can talk more about this. I know that that's something that is kind of a larger topic. And then another thing I think where the two are really similar is there's this endless learning that goes with each of them. I guess that's true of, I think, most crafts. Good practitioners of the craft, I think, take on that mindset. But I do think that obviously, in engineering, you have industry changes, new technologies emerging really frequently. But I do think that good writers think about that, too, in terms of what new novels are coming out. But also, how do you build a solid foundation? And I do think it's that contrast that applies in any craft is, you know, you want to have a good solid foundation and learn the basics but then keep up to date with new things as well. So I think there was this...there's this meme I actually did include in the newsletter that was...it's the meme of these two guys looking at different windows of a bus, and one looks really sad, and one looks really happy. But the two of them have the same caption, which is there's always more to learn. And so I think that is the two sides of the coin [laughs]. I think that is relevant in engineering and writing that I've kind of brought to both of those practices is trying to be optimistic [laughs] about the idea that there's always more to learn that that's kind of the thought of it. And then certainly, when it comes to management, I do think that writing has proven really valuable in that very obvious sense of kind of practical communication where I just write a lot more. I write a lot more things that are not code, I should say, as a manager. And communication is really at the forefront of my job, and so is demonstrating curiosity and building empathy, fostering relationships with people. And I do think that particularly writing fiction you have to be curious about people I think to be a writer. And I think that is true of managers as well. So I do think that has been a really interesting way that I didn't anticipate writing showing up in my day job but has been a really helpful thing and has made my work stronger and think about the people, the process, and kind of what we do and why a little differently. STEPHANIE: Yeah, absolutely. Wow, you got into a lot of different things I'm excited to keep discussing further. But one thing that I was thinking about as you were talking was, have you heard of the adage, I guess, that code is read many more times than it's written? NICOLE: Hmm, I think I have, yeah. STEPHANIE: I was thinking about that as you were talking because, in some ways, in most ways, actually, if you ascribe to that adage, I suppose, we write code for others to read. And I think there's an aspect of code telling a story that is really interesting. I've heard a lot of people advocate for writing, thoughtbot included, writing your tests like they're telling a story. And so when a future developer is trying to understand what's going on, they can read the tests, understand the setup, read what is being tested, and then read what the expected outcome is and have a complete picture of what's going on. The same goes for commit messages. You are writing little bits of documentation for people in the future. And I've also been thinking about how legacy code is just this artifact as well of all of the changes that an organization might have gone through. And so when you see something that you see a bit of code that is really weird or gets your spidey senses tingling, it's almost like, oh, I wonder what happened here that led to this piece left behind? NICOLE: Yeah, definitely. Now that you're talking about it, I also think of pull requests as a great way to employ storytelling. I remember there definitely have been times where myself or other engineers are working on a really thorny problem, and we always joke that the PR description is longer than the change. And it's like, but you got to read the PR description in order to understand what change you're making and why. And here's the backstory, the context to kind of center people in that. As a manager, I think about storytelling a lot in terms of defining purpose and providing clarity for teams. I was reading Julie Zhuo's "The Making of a Manager," and it was a really kind of foundational text for me when I first was exploring management. And she kind of boils it down to people, purpose, and process. And so I do think the purpose part of that is really tied to clear communication. And can you tell a story of what we're doing from really high-level vision and then more tactically strategy? And then making sure that people have bought into that, they understand, can kind of repeat that without you being there to remind them necessarily. Because you really want that message to carry through in the work and that they have that understanding. Vision is something I only recently have really started to realize how difficult it is to articulate. It's like you don't really understand the purpose of vision until you maybe don't have one, or you've been kind of just trying to keep your head afloat, and you don't have a Northstar to work towards. But I do think that is what plays into motivation, and team health, and, obviously, quality of the product. So yeah, that's kind of another dimension I've been thinking of. And also our foes actually. Sorry, another one. Our foes, I think, like outages and incidents. I think that's always a fun opportunity to talk about stories. There was a period of time where every time we had an incident, you had to present that incident and a recap of it in an engineering all-hands every month. And they ended up being really fun. We turned something that is ostensibly very stressful into something that was very entertaining that people could really get on board with and would learn something from. And we had the funniest one; I think was...we called it the Thanks Obama Outage because there was an outage that was caused by a photo of Barack Obama that had been uploaded in our content management system, as required no less, that had some malformed metadata or something that just broke everything. And so, again, it was a really difficult issue [laughs] and a long outage. And that was the result that I remember that presentation being really fun. And again, kind of like mythmaking in a way where that is something that we remember. We pay attention to that part of the codebase a lot now. It's taught us a lot. So yeah, I do think storytelling isn't always necessarily the super serious thing, but it can also just be team building, and morale, and culture as well. STEPHANIE: Yeah, absolutely. I think what you said about vision really resonates with me because if you don't have the vision, then you're also not making the best decisions you can be making even something as low-level as how you write the code. Because if you don't know are we going to be changing this feature a month from now, that might dictate how you go forth with implementation as opposed to if you know that it's not in the company's vision to really be doing anything else with this particular feature. And you then might feel a little more comfortable with a more rudimentary approach, right? NICOLE: Yeah, totally. Whether or not it's, we've over-optimized or not or kind of optimized for speed. Like, it's all about trade-offs. And I do think, again, like you said, having a vision that always you can check your decision-making against and inform the path ahead I think is very, very helpful. STEPHANIE: When you write, do you also keep that in mind? Like, do you write with that North Star? And is that really important to your process? NICOLE: I think it depends. I think that writing can be a little more at a slant, I suppose, is how I think of it because I don't always...just similar to work, I don't always come in with a fully-fledged fleshed-out vision of what I want a piece to be. The most recent piece I've been working on actually I did have kind of a pretty, I think, solid foundation. I've been working on this story about loneliness. And I knew that I wanted to base the structure on the UCLA...a UCLA clinic has this questionnaire that's 20 items long that is about measuring loneliness on a scale. And so I was like, okay, I knew that I wanted to examine dimensions of loneliness, and that would be the structure. It would be 20 questions, and it would be in that format. So that gave me a lot more to start with of, you know, here's where I want the piece to go. Here's what I want it to do. And then there have definitely been other cases where it's more that the conceit seems interesting; a character comes to mind. I overhear a conversation on the subway, and I think it's funny, and that becomes the first thing that is put on the page. So I definitely have different entry points, I think, into a draft. But I will definitely say that revision is the phase where that always gets clarified. And it has to, I think, because as much as I'm sometimes just writing for vibes, it's not always like that. And I do think that the purpose of revision is to clarify your goals so you can then really look at the piece and be like, is it doing what I want it to? Where is it lacking? Where's it really strong? Where's the pacing falling flat? And things like that. So I do think that sooner or later, that clarity comes, and that vision comes into focus. But it isn't always the first thing that happens, I think, because I do think the creative process is a little bit more mysterious, shall we say, than working on an engineering team. [laughs] STEPHANIE: Yeah. Well, you started off responding to my question with it depends, which is a very engineering answer, but I suppose -- NICOLE: That is true. That is true. You got me. [laughs] STEPHANIE: It applies to both. MID-ROLL AD: Debugging errors can be a developer's worst nightmare...but it doesn't have to be. Airbrake is an award-winning error monitoring, performance, and deployment tracking tool created by developers for developers that can actually help cut your debugging time in half. So why do developers love Airbrake? It has all of the information that web developers need to monitor their application - including error management, performance insights, and deploy tracking! Airbrake's debugging tool catches all of your project errors, intelligently groups them, and points you to the issue in the code so you can quickly fix the bug before customers are impacted. In addition to stellar error monitoring, Airbrake's lightweight APM helps developers to track the performance and availability of their application through metrics like HTTP requests, response times, error occurrences, and user satisfaction. Finally, Airbrake Deploy Tracking helps developers track trends, fix bad deploys, and improve code quality. Since 2008, Airbrake has been a staple in the Ruby community and has grown to cover all major programming languages. Airbrake seamlessly integrates with your favorite apps to include modern features like single sign-on and SDK-based installation. From testing to production, Airbrake notifiers have your back. Your time is valuable, so why waste it combing through logs, waiting for user reports, or retrofitting other tools to monitor your application? You literally have nothing to lose. Head on over to airbrake.io/try/bikeshed to create your FREE developer account today! STEPHANIE: You mentioned revision. And so, I do want to talk about feedback because I think that is an important part of the revision process. And I have really loved what you've had to say about writing feedback and your experience with writing feedback, especially in writing workshops. And I have always been really curious about what we might be able to learn about receiving feedback in code review. NICOLE: When it comes to receiving feedback, I think I wrote a two-part series of my newsletter, one that was about providing feedback, one that was about receiving it. I think on the side of receiving feedback, first and foremost, I think it's important to know when you're ready to share your work and know that you can share multiple times. In writing, that can be I show a very early draft to my partner who is the person who kind of reads everything and anything at any stage. It's something less polished, and I'm really just testing ideas. But then obviously, if there's something that is more polished, that is something I would want to bring to a writing group, bring into a workshop, things like that. Similarly, as engineers, I think...thank God for GitHub drafts actually adopting literally the way in which I think of that, right? STEPHANIE: Yeah. NICOLE: You can share a branch or a GitHub PR in progress and just check the approach. I've done that so many times, and really that helped so much with my own learning and learning from mentors in my own organization was checking in early and trying to gut-check my work earlier as opposed to later. Because then you feel, I think, again, a bit more naturally receptive because you're already in that questioning phase. You're not like, oh, this is polished, and I've written all the tests, and the PR description is done. And now you want me to go back and change the whole approach from the ground up. That can feel tough. I get that. And so I think, hand in hand, what goes with that is whose feedback are you interested in? Is that a peer? Is it a mentor? I think obviously leaning on your own team, on senior engineers, I do think that is one of the primary, I think, expectations of a senior engineer is kind of multiplying the effectiveness of their peers and helping them learn and grow. So I do think that that's a really valuable skill to develop on that end, but also, again, just approaching people. And obviously, different teams have different processes for that, if it's daily stand-ups, if it's GitHub reminders, automated messages that get pulled up in your channel, things like that. But there are ways to build that into your day-to-day, which I think is really beneficial too. And then there's also the phase of priming yourself to receive the feedback. And I think there's actually a lot of emotional work that I don't think we talk about when it comes to that. Because receiving feedback can always be vulnerable, and it can bring up unexpected emotions. And I think learning how to regulate the emotional response to that is really valuable for us as people but obviously within the workplace too. So I've found it really helpful to reflect if I'm getting feedback that...well, first of all, it depends on the format. So I think some people prefer verbal feedback, some people will prefer written. I think getting it in the form of written feedback can be helpful because it provides you some distance. You don't have to respond in the moment. And so I've definitely had cases where I then kind of want to reflect on why certain suggestions might elicit certain reactions if I have a fight or flight response, if I'm feeling ashamed or frustrated, or indignant, all the range of emotions. Emotions are, to put the engineering hat on, are information. And so I think listening to that, not letting it rule you per se but letting it inform and help you figure out what is this telling me and how do I then respond, or what should I do next? Is really valuable. Because sometimes it's not, again, actually the feedback; maybe it's more about that, oh, it's a really radical idea. Maybe it's a really...it's an approach I didn't even consider, and it would take a lot of work. But again, maybe if I sit and think about it, it is the scalable approach. It's the cleaner approach, things like that. Or are they just touching on something that I maybe haven't thought as deeply about? And so I think there is that piece too. Is it the delivery? Is it something about your context or history with the person giving the feedback too? I think all of those, the relationship building, the trust on a team, all plays into feedback. And obviously, we can create better conditions for exchanging and receiving feedback. But I do think there's still that companion piece that is also just about, again, fostering team trust and culture overall because that is the thing that makes these conversations all the easier and less, I think, potentially fraught or high pressure. STEPHANIE: 100%. Listeners can't see, but I was nodding very aggressively [laughs] this entire time. NICOLE: Loved it. STEPHANIE: And I love that you bring up interpersonal relationships, team culture, and feelings. Listeners of the show will know that I love talking about feelings. But I wanted to ask you this exact question because I think code review can be so fraught. And I've seen it be a source of conflict and tension. And I personally have always wanted more tools for giving better feedback. Because when I do give feedback, it's for the person to feel supported to help push their work to be better and for us to do good work as a team. And I am really sensitive to the way that I give feedback because I know what it's like to receive feedback that doesn't land well. And when you were talking about investigating what kinds of feelings come up when you do receive a certain kind of comment on a code review or something, that was really interesting to me. Because I definitely know what it's like to have worked really, really hard on a pull request and for it to feel very precious to me and then to receive a lot of change requests or whatever. It can be really disappointing or really frustrating or whatever. And yeah, I wish that we, as an industry, could talk about this stuff more frequently. NICOLE: Yeah, for sure. And I do think that you know, I think the longer you work with someone, ideally, again, the stronger relationship you form. You find your own ways of communicating that work for you. I think actually what I've learned in management is, yes, I have a communication style, but I also am flexible with how I work with each of my reports, who, again, have very different working styles, communication styles, learning styles. I don't believe that the manager sets the standards. I think there is a balance there of meeting people where they are and giving them what they need while obviously maintaining your own values and practices. But yeah, certainly, again, I think that's why for perhaps more junior engineers, they might need more examples. They might not respond well to as terse a comment. But certainly, with engineers, senior engineers that I've worked with, when I was starting out, the more we developed a relationship, they could just get a little bit more terse. For example, they could be like, "Fix this, fix that," and I would not take it personally because we had already gone through the phase where they were providing maybe some more detailed feedback, links to other examples or gists, or things like that, and our communication styles evolved. And so I do think that's another thing to think about as well is that it doesn't have to be static. I think that's the value of a team, and having good team process, too, is ideally having arenas in which you can talk about how these kinds of things are going. Are we happy with the cadence? Are we happy with how people are treating each other and things like that? Are we getting timely feedback and things like that? That's a good opportunity for a retrospective and to talk about that in a kind of blameless context and approach that more holistically. So I do think that, yeah, feedback can be very fraught. And I think what can be difficult in the world of engineering is that it can be very easy to then just be like, well, this is just the best way for the work. And feelings are, like you said, not really kind of considered. And, again, software development and engineering is a team sport. And so I do think fostering the environment in which everyone can be doing great work is really the imperative. STEPHANIE: Yeah, I really like how you talked about the dynamic nature of relationships on a team and that the communication style can change there when you have built that trust and you understand where another person is coming from. I was also thinking about the question of whose feedback are you interested in? And I certainly can remember times where I requested a review from someone in particular because maybe they had more context about this particular thing I was working on, and I wanted to make sure that I didn't miss anything, or someone else who maybe I had something to learn from them. And that is one way of making feedback work for me and being set up to receive it well. Because as much as...like you said, it's really easy to fall back into the argument of like, oh, what's the best way for the work, or what is the cleanest code or whatever? I am still a person who wrote it. I produced a piece of work and have feelings about it. And so I have really enjoyed just learning more about how I react to feedback and trying to mitigate the stress that I feel in what is kind of inherently like a conflict-generating process. NICOLE: Yeah, yeah, definitely. Another thing that kind of popped into my head to one of the earlier questions we were talking about is in terms of similarities between writing and engineering, style and structure are both really, really important. And even though in engineering, like you said, sometimes it can be, I mean, there is a point with engineering where you're like, this line of code works, or it doesn't. There is a degree of correctness [laughs] that you do have to meet, obviously. But again, after that, it can be personal preference. It's why we have linters that have certain styles or things like that to try to eliminate some of these more divisive, shall we say, potentially discussions around, [laughs] God forbid, tabs or spaces, naming conventions, all this stuff. But certainly, yeah, when it comes to structuring code, the style, or whatever else, like you said, there's a human lens to that. And so I think making sure that we are accounting for that in the process is really important, and not just whether or not the work gets done but also how the work gets done is really important. Because it predicts what do future projects...what does future collaboration look like? And again, you're not just ever optimizing for one thing in one point of time. You're always...you're building teams. You're building products. So there's a long kind of lifecycle to think about. STEPHANIE: For sure. So after you get feedback and after you go through the revision process, I'm curious what you think about the idea of what is good enough in the context of your writing. And then also, if that has influenced when you think a feature is done or the code is as good as you want it to be. NICOLE: Yeah, definitely. I think when it comes to my writing, how I think about what is good enough I think there is the kind of sentiment common in the writer community that you can edit yourself to death. You can revise forever if you wanted to. It's also kind of why I don't like to go back and read things I've already published because I'm always going to find something, you know, an errant comma or like, oh, man, I wish I had rephrased this here. But I do think that, for me, I think about a couple of questions that help me get a sense of is this in a good place to, you know, for me generally, it's just to start submitting to places for publication. So one of those is, has someone else read it? That is always a really big question, whether it's a trusted reader, if I brought it to a workshop, or just my writing group, making sure I have a set of outside eyes, fresh eyes on the piece to give their reaction. And again, truly as a reader, sometimes just as a reader, not even as a fellow writer, because I do think different audiences will take different things and provide different types of feedback. Another one is what kinds of changes am I making at this point in time? Am I still making really big structural edits? Or am I just kind of pushing words and commas around, and it feels like rearranging deck chairs on the Titanic? They're not massive changes to the piece. And then the final question is always, if this were published in its current state right now, would I be happy with it? Would I be proud of it? And that's a very gut feeling that I think only an individual can kind of feel for themselves. And sometimes it's like, no, I don't like the way, like, I know it's 95% there, but I don't like the way this ends or something else. Again, those are all useful signals for me about whether a piece is complete or ready for submission or anything like that. I think when it comes to engineering, I think there's a little bit less of the gut feeling, to be honest, because we have standards. We have processes in place generally on teams where it's like, is the feature working? Have you written tests? Have you written a QA plan if it needs one? If it's something that needs more extensive documentation or code comments or something like that, is that something you've done? Has a bit more of a clear runway for me in terms of figuring out when something is ready to be shown to others. But certainly, as a manager, I've written a lot more types of documents I suppose, or types of communication where it's like organizational changes. I've written team announcements. I've written celebration posts. I've had to deliver bad news. Like, those are all things that you don't think about necessarily. But I've definitely had literally, you know, I have Google Docs of drafts of like, I need to draft the Slack message. And even though it's just a Slack message, I will spend time trying to make sure I've credited all the right people, or provided all the context, got all the right answers. I run it by my director, my peers, and things like that if it's relevant. And again, I think there is still that piece that comes in of drafting, getting feedback, revising, and then feeling like, okay, have I done my due diligence here, and is it ready? That cycle is applicable in many, many situations. But yeah, I certainly think for direct IC work, it's probably a little bit more well-defined than some of the other processes. STEPHANIE: Yeah, that makes sense. I really liked what you said about noticing the difference between making big structural changes and little word adjustments. I think you called it pushing commas around or something like that. NICOLE: [laughs] Yeah. STEPHANIE: I love that. Because I do think that with programming, there is definitely a big part of it that's just going on the journey and exploring different avenues. And so if you do suddenly think of, oh, I just thought of a completely different way to write this code, that is worth exploring even if you just end up going back to the original implementation. But at least you saw that thought through, and you're like, okay, this doesn't work because of X, Y, and Z, and I'm choosing to go this other route instead. And I think that, yeah, that is just a good practice to explore. NICOLE: Another example of storytelling, too, where it's like, you can tell the story in the PR description or whatever, in stand-up, to be like, I also did go down this path, XYZ reason. Here's why it didn't work out, and here's what we're optimizing for. And there you go. So I do think we talk...I guess product managers think more about buy-in, but I think that's true of engineers too. It's like, how do you build consensus and provide context? And so yeah, I think what you were saying, too, even if the path is circuitous or you're exploring other avenues, talking to other people, and just exploring what's out there, it all adds up to kind of the final decision and might provide, again, some useful information for other people to understand how you arrived there and get on board with it. STEPHANIE: 100%. I remember when I worked with someone who we were writing a PR description together because we had paired on some code. And we had tried three different things. And he wrote paragraphs for each thing that we tried. And I was like, wow, I don't know if I would have done that on my own. But I just learned the value of doing that to, like you said, prime yourself for feedback as well, being like, I did try this, and this is what I thought. And other people can disagree with you, but then at least they have the information, right? NICOLE: Definitely. STEPHANIE: So before we wrap up, the last thing that I wanted to talk about, because I think it's super cool, is just how you have a totally separate hobby and skill and practice that you invest time and energy into that's not programming. And it's so refreshing for me to see you do that because I think, obviously, there's this false idea that programmers just code all the time in their free time, in their spare time, whatever. And I'm really curious about how writing fits into your life as something separate from your day job. NICOLE: Yes, I've been thinking about this a ton. I think a lot of people, the last couple of years has forced a really big reckoning about work and life and how much we're giving to work, the boundaries that can be blurred, how capitalism butts its head into hobbies, and how we monetize them, or everything is a side hustle. And, oh, you should have a page running...oh, you should charge for a newsletter. And I think there's obviously the side of we should value our labor, but also, I don't want everything in my life to be labor. [laughs] So I do think that is interesting. Writing to me, I actually do not see it as a hobby. I see it as another career of mine. I feel like I have two careers, but I have one job, [laughs] if that makes sense. I certainly have hobbies. But for me, what distinguishes that from my writing is that with hobbies, there's no expectation that you want to get better. You approach it with just...it's just pure enjoyment. And certainly, writing has part of that for me, but I have aspirations to publish. I love it when my work can reach readers and things like that. But I do think that regardless having other interests, like you said, outside engineering, outside technology, it's a great break. And I do think also in technology, in particular, I notice...I think we're getting away from it, but certainly, there's an expectation, like you said, that you will have side projects that you code in your free time, that you're on Hacker News. I think there is a little bit of that vibe in the tech industry that I don't see in other industries. You don't expect a teacher to want to teach in their free time, [laughs] you know what I mean? But we have almost that kind of implicit expectation of engineers to always be staying up to date on those things. I think with writing and engineering; the two complement each other in some interesting ways. And they make me appreciate things about the other craft or practice that I may not previously have. And I think that with engineering, it is a team effort. It's really collaborative, and I really love working in that space. But on the flip side, too, with writing, I do love, you know, there's the ego part of it. You don't have individual authorship over code necessarily unless it's git blame level. But there's a reason why it's called git blame, [laughter] even the word is like git blame. I've literally had cases where I'm like, oh, this thing is broken. Who wrote this? And then I was like, oh, surprise, it was you six years ago. But I do think with writing; it's an opportunity for me to really just explore and ask questions, and things don't have to be solved. It can just be play. And it is a place where I feel like everything that I accomplish is...obviously, I have people in my life who really support me, but it is a much more individual activity. So it is kind of the right-left brain piece. But I've been reading this book called "Saving Time." It is what my microphone is currently propped on. But it's by Jenny Odell, who wrote: "How to Do Nothing." It's breaking my brain in a really, really, really good way. It talks a lot about the origin of productivity, how we think about time, and how it is so tied to colonialism, and racism, and capitalism, and neoliberalism, all these things. I think it has been really interesting. And so thinking about boundaries between work and writing has been really, really helpful because I really love my job; I'm not only my job. And so I think having that clarity and then being like, well, what does that mean in terms of how I divide my time, how I set examples for others at work in terms of taking time off or leaving the office on time? And trying to make sure that I have a good emotional headspace so that I can transition to writing after work; all those things. I think it is really interesting. And that also, ultimately, it's we're not just our productivity either. And I think writing can be very, again, inherently kind of unproductive. People joke that cleaning is writing, doing the dishes is writing, taking a walk is writing, showering is writing, but it is true. I think that the art doesn't talk about efficiency. You can't, I think, make art always more efficient in the same way you can do with engineering. We don't have those same kinds of conversations. And I really like having that kind of distinction. Not that I don't like problem-solving with constraints and trade-offs and things like that, but I also really like that meandering quality of art and writing. So yeah, I've been thinking a lot more about collective time management, I guess, and what that means in terms of work, writing, and then yeah, hobbies and personal life. There are never enough hours in the day. But as this book is teaching me, again, maybe it's more about paradigm shifting and also collective policies we can be putting in place to help make that feeling go away. STEPHANIE: For sure. Thank you for that distinction between hobby and career. I really liked that because it's a very generative mindset. It's like a both...and... rather than an either...or... And yeah, I completely agree with you wanting to make your life expansive, like, have all of the things. I'm also a big fan of Jenny Odell. I plugged "How to Do Nothing" on another episode. I am excited to read her second book as well. NICOLE: I think you'll like it a lot. It's really excellent. She does such interesting things talking about ecology and geology and geographic time skills, which is really interesting that I don't know; it's nice to be reminded that we are small. [laughter] It's a book that kind of reminds you of your mortality in a good way, if that makes sense. But much like Gary on your porch reminds you of mortality too [laughs] and that you have to put Gary away for a little bit so that his time can come in October. [laughs] STEPHANIE: Exactly, exactly. Cool. On that note, let's wrap up. Thank you so much for being on the show, Nicole. NICOLE: Thank you so much for having me. This was a blast. STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
Joël has been integrating a third-party platform into a testing pipeline...and it has not been going well. Because it's not something she usually keeps up-to-date with, Stephanie is excited to learn about more of the open-source side of things in Ruby, what's new in the Ruby tooling world, and what folks are thinking about regarding the future of the language. Today's topic is inspired by an internal thoughtbot Slack thread about writing a custom matcher for Rspec. Stephanie and Joël contrast DSLs vs. Object APIs and also talk about: CanCanCan vs Pundit RSpec DSL When is a DSL helpful? Why not use both DSLs & Object APIs? Extensibility When does a DSL become a framework? This episode is brought to you by Airbrake (https://airbrake.io/?utm_campaign=Q3_2022%3A%20Bike%20Shed%20Podcast%20Ad&utm_source=Bike%20Shed&utm_medium=website). Visit Frictionless error monitoring and performance insight for your app stack. RubyKaigi 2023 (https://rubykaigi.org/2023/) Mystified by RSpec's DSL? by Jason Swett (https://www.codewithjason.com/mystified-rspecs-dsl-parentheses-can-add-clarity/) Building Custom RSpec Matchers with Regular Objects (https://thoughtbot.com/blog/building-custom-rspec-matchers-with-regular-objects) FactoryBot (https://github.com/thoughtbot/factory_bot) Writing a Domain-Specific Language in Ruby by Gabe Berke-Williams (https://thoughtbot.com/blog/writing-a-domain-specific-language-in-ruby) Capybara (https://teamcapybara.github.io/capybara/) Acceptance Tests at a Single Level of Abstraction (https://thoughtbot.com/blog/acceptance-tests-at-a-single-level-of-abstraction) CanCanCan (https://github.com/CanCanCommunity/cancancan) Pundit (https://www.capvidia.com/products/pundit) Discrete Math and Functional Programming (https://www.amazon.com/Discrete-Mathematics-Functional-Programming-VanDrunen/dp/1590282604) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a little bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: I've been integrating a third-party platform into our testing pipeline for my client. It has not been going well. We've been struggling a little bit, mostly just because tests just kind of crash. Our testing pipeline is pretty complex. It's a lot of one script, some environment variables, does a few things, shells out to another script, which is in a different language. Does a few more things, shells out to another script, maybe calls out to rake, calls out to a shell script. There are four or five of these in a chain, and it's a bit of a mess. Somewhere along in there, something is not compatible with this third-party service that we're trying to integrate with. I was pairing this week with a colleague. And we were able to reproduce a situation where we were able to get a failure under some conditions and a success under other conditions. So these are basically, if we run the whole chain of scripts that call each other from the beginning, we know we get a failure. And if we skipped entirely the chain of scripts that set up things and then just manually try to invoke a third-party service, that works. And so now we know that there's something in between that's incompatible, and now it's just about narrowing things down. There are a few different approaches we could take. We could try to sort of work our way forward. We know a known point where it breaks and then just try to start the chain one step further and see where it fails. We could try to get fancy and do a binary search, like split it in half and then half and half again. We ended up doing it the other way, where we started at the end. We had our known good point and then just stepping one step back and saying, okay, now we introduce the last script in the chain. Does that work? Okay, that pass is great. Let's go one step further; two scripts up in the chain. And at some point, we find, okay, here's the one script that fails. Now, what is it within this script? And it was a really fun debugging session where we were just narrowing things down until we found the source of the bug. STEPHANIE: Wow, that sounds pretty complicated. It just seems like there are so many layers going on. And it was really challenging to pinpoint where the source of the issue was. JOËL: Definitely. I think all the layers made it really complicated. But having a process that we could follow and then kind of narrowing it down made it almost mechanical to figure out where the bug was once we got to a point where we had a known good point and a known bad point. STEPHANIE: Yeah, that makes sense. Kind of sounds like if you are using git bisect or something like that to narrow down the scope of where the issue could be. I'm curious because this is like a bunch of shell scripts and rake tasks or commands or whatever. What would have made this debugging process easier? JOËL: I think having fewer scripts in this chain. STEPHANIE: [laughs] That's fair. JOËL: We don't need so many scripts that call out to each other in different languages trying to share data via environment variables. So we've got a bit of a Rube Goldberg machine, and we're trying to patch in yet another piece in there. STEPHANIE: Yeah, that's really tough. I was curious if there was, I don't know, any logging or any other clues that you were getting along the way because I know from experience how painful it is to debug that kind of code. JOËL: It's interesting because I feel like normally logging is something that's really useful. In this particular case, we run into an exception at some point. So it's more of under what conditions does the exception happen? The important thing was to find that there is a point where it breaks, and there's a point where it doesn't, and realizing that if we ran some of these commands just directly without going through the whole pipeline, that things did work and that we were not triggering that exception. So all of a sudden, now that tells us, okay, something in our pipeline is wrong. And then we can just start narrowing things down. So yeah, adventures in debugging. Sometimes it's really frustrating, but then when you have a good process, and you find the bug, it's incredibly satisfying. STEPHANIE: I like that you used a process that can be applied to many different problems, in this particular case, debugging a testing pipeline. Maybe not something that we do every day, but certainly, it comes up, and now we have tools to address those kinds of issues as well. JOËL: So my week has been up and down with all of this debugging. What's been new in your world? STEPHANIE: I've been doing some travel planning because I'm going to RubyKaigi in Japan. JOËL: Whoa. STEPHANIE: This is actually going to be my first international conference, so I'm really looking forward to that. I just have never been compelled to travel abroad to go to a tech conference. But I'm really looking forward to going to RubyKaigi because now I've been to the U.S.-based conferences a few times. And I'm excited to see how things are different at an international conference and specifically a RubyKaigi because, obviously, there's a lot of really cool Ruby work happening over there in Japan. So I'm excited to learn about more of the open-source side of things of Ruby, what's new in the Ruby tooling world, and just what folks are thinking about in terms of the future of the language. That's not something I normally keep super up-to-date on. But I'm excited to be around people who do think and talk about these things a lot and maybe get some new insights into my own work. JOËL: Do you find that you tend to keep up more with some of the frameworks like Rails rather than the underlying language itself? STEPHANIE: Yeah, that's a good question. I do think because the framework changes a little more frequently, new releases are kind of more applicable to the work that I'm doing. Whereas language updates or upgrades are a little bit less top of mind for me because the point is that it doesn't have to change [laughs] all that much, and we can continue to work with things as expected and not be disrupted. So it is definitely like a whole new world for me, but I'm really looking forward to it. I think it will be really interesting and just kind of a whole other space to explore that I haven't really because I've usually been focused on more of the web development and industry work side of things. JOËL: What's a Ruby feature that either is coming out in the future or that came out in the last couple of releases that got you really excited? STEPHANIE: I think the conversation about typing in Ruby is something that has been on my radar but has also been ebbing and flowing over time. And I did see a few talks at RubyKaigi this year that are going to talk about how to introduce gradual typing in Ruby. And now that it has been out for a little bit and people have been using it, how people are feeling about it, pros and cons, and kind of where they're going to take it or not take it from there. JOËL: Have you done much TypeScript? STEPHANIE: I have been working more in TypeScript recently but did spend most of my front-end work coding days in JavaScript. And so that transition itself was pretty challenging for me where I suddenly felt a language that I did know pretty well. I was having to be in that...in somewhat of a beginner's mindset again. Even just reading the code itself, there were just so many new things to be looking at in terms of the syntax. And it was a difficult but ultimately pretty rewarding experience because the way I thought about JavaScript afterwards was much more refined, I think. JOËL: Types definitely, I think, change the way you think about code; at least, that's been my experience. STEPHANIE: Yeah, absolutely. I haven't gotten the pleasure to work with types in Ruby just yet, but I've just heard different experiences. And I'm excited to see what experts have to say about it. JOËL: That's the fun of going to a conference. STEPHANIE: Absolutely. So yeah, if any listeners are also headed to RubyKaigi, yeah, look out for me. JOËL: I was recently having a conversation with someone about the fact that a lot of languages provide ways to sort of embed many languages within them. So the Lisp family of languages are really big into macros and metaprogramming. Some other languages are big into giving you the ability to build your own ASTs or have really strong parsing capabilities so that you can produce your own, again, mini-language. And Ruby does this as well. It's pretty popular among the Ruby community to build DSLs, Domain-Specific Languages using some of Ruby's built-in abilities. But it seems to be a sort of universal need or at the very least a universal desire among programmers. Have you ever found yourself as a code author wanting to embed a sort of smaller language within your application? STEPHANIE: I don't think I have, to be honest. It's a very interesting question. Because I think the motivation to build your own mini-language using Ruby would have to be you'd have to have a really good reason for it, and in my experience, I haven't quite encountered that yet. Because, yeah, it seems like a lot of upfront work, a lot of overhead to introduce something like that, especially if it's not necessarily either a really, really particular domain that others might find a use for, or it just doesn't end up seeming worthwhile if I can just write regular, old Ruby code. JOËL: I think you're not alone. I think the Ruby community has been kind of a bit of a pendulum here where several years ago, everything that could be made into a DSL was. Now the pendulum kind of has been swinging the other way. And we see DSLs, but they're not quite as frequent. For those who maybe have not experienced a DSL or aren't quite familiar with the concept, how would you describe the idea? STEPHANIE: I think I would describe domain-specific languages as a bit of a mini-language that is created for a very particular problem space in mind to make development for that domain easier. Oftentimes, I've also kind of seen people describe the benefit of DSLs as being able to read that language as if it were plain English. And so, in my head, I have kind of, at least in the Ruby world, right? We see that a lot in different gems. RSpec, for example, has its own internal DSL, and many people really enjoy it because it took the domain of testing. And the way you write it kind of is how you might read or understand it in English. And so it's a bit easier to talk about what you're expecting in your tests. JOËL: Yeah, it's so high-level and minimal and domain-specific that it almost stops feeling like it's a programming language and can almost feel like it's a high-level configuration for this very particular domain, sometimes even to the point where the idea is that a non-programmer could read it and understand what's going on. STEPHANIE: I think RSpec is actually one of the first Ruby DSLs that you might encounter when you're learning Ruby for the first time. And I've definitely seen developers who are new to Ruby, you know, they're writing code, and they're like, okay, I'm ready to write a test now. And the project uses RSpec because that's what most of us use in our Rails applications. And then they see, like you said, almost a configuration language, and they are really confused. They're not really sure what they're reading. They struggle with the syntax a lot. And it ends up being a point of frustration when they're first starting out if they're not just copying and pasting other existing RSpec tests. I'm curious if you've seen that before. JOËL: I've definitely seen that. And it's a little bit ironic because oftentimes, an argument for DSL is that it makes things simpler that you don't even have to know Ruby; you can just write it. It's simpler. It's easier to write. It's easier to understand. And to a certain extent, maybe that's true. But for someone who does know Ruby and doesn't know your particular little domain language, now they're encountering something that they don't know. And they're having to learn it, and they're having to struggle with it. And it might behave a little bit weirdly compared to how Ruby normally works. And so sometimes it doesn't make it easier for adoption. But it does look really good in a README. STEPHANIE: That's totally fair. I think the other thing that's interesting about RSpec is that a lot of it is really just stylistic. I actually read a blog post by Jason Swett and the headline of it was "Mystified by RSpec's DSL? Some parentheses can add clarity." And he basically goes on to tell us that really RSpec is just leaning on some of Ruby's syntactic sugar of omitting parentheses for method calls. And if you just add the parentheses back in your it blocks or your describes, it can read a lot more like regular Ruby. And you might have a better time understanding what's going on when you realize that we're just passing our descriptors as arguments along with some blocks. JOËL: That's ironic given that oftentimes, the goal of these is to make it look like not Ruby. STEPHANIE: I agree; it is ironic. [laughs] MID-ROLL AD: Debugging errors can be a developer's worst nightmare...but it doesn't have to be. Airbrake is an award-winning error monitoring, performance, and deployment tracking tool created by developers for developers that can actually help cut your debugging time in half. So why do developers love Airbrake? It has all of the information that web developers need to monitor their application - including error management, performance insights, and deploy tracking! Airbrake's debugging tool catches all of your project errors, intelligently groups them, and points you to the issue in the code so you can quickly fix the bug before customers are impacted. In addition to stellar error monitoring, Airbrake's lightweight APM helps developers to track the performance and availability of their application through metrics like HTTP requests, response times, error occurrences, and user satisfaction. Finally, Airbrake Deploy Tracking helps developers track trends, fix bad deploys, and improve code quality. Since 2008, Airbrake has been a staple in the Ruby community and has grown to cover all major programming languages. Airbrake seamlessly integrates with your favorite apps to include modern features like single sign-on and SDK-based installation. From testing to production, Airbrake notifiers have your back. Your time is valuable, so why waste it combing through logs, waiting for user reports, or retrofitting other tools to monitor your application? You literally have nothing to lose. Head on over to airbrake.io/try/bikeshed to create your FREE developer account today! JOËL: I think another drawback that I've seen with DSLs is that they oftentimes are more limited in their capabilities. So if the designer of the gem didn't explicitly think of your use case, then oftentimes, it can be really hard to extend or to support edge cases that are not specifically designed for that language in the way that plain Ruby is often much more flexible. STEPHANIE: Yeah, that's really interesting because when a gem does have some kind of DSL, a lot of effort probably went into making that the main interface that you would work with or you would use. And when that isn't working for your use case, the design of the underlying objects may or may not be helpful for the changes that you want to make. JOËL: I think it's interesting that you mentioned the underlying objects because those are often sort of not meant for public consumption when you're building a gem that's DSL forward. I think, in many cases, my ideal gem would make those underlying objects the primary interface and then maybe offer DSL as a kind of nice-to-have layer on top for those situations that maybe aren't as complex where writing things in the domain language might actually be quite nice. But keeping those underlying objects as the interface, it's nice to use and well-documented for the majority of people. STEPHANIE: Yeah, I like that too because then you can get the best of both worlds. So speaking of trying to make a DSL work for you, have you ever experienced having to kind of work around the DSL to get the functionality you were hoping to achieve? JOËL: So I think we're talking about the idea of having both a DSL and the underlying objects. And RSpec is a great example of this with their custom matchers. RSpec itself is a DSL, but then they also offer a DSL to allow you to create custom matchers. And it's not super well documented. I always forget how to define them, and so I oftentimes don't bother. It's just kind of too much of a pain for something that doesn't always provide that much value. But if it were easy, I would probably do it more. Eventually, I realized that you could use just regular Ruby objects as custom matchers. And they just seemed to respond to certain methods, just regular old objects and polymorphism. And all of a sudden, now I'm back into all of the tools and mechanisms that I am familiar with, like the back of my hand. I can write objects all day. I can TDD them. I can apply any patterns that I want to if I'm doing something really complicated. I can extract helpers. All of that works really well with the knowledge that I already have without having to sink a lot of time into trying to learn the built-in DSL. So, for the most part, now, when I define custom matchers, I'll often jump directly to creating a regular object and making it conform to the matcher interface rather than relying on the DSL for that. So once we go back to the test, now we're back in DSL land. Now we're no longer talking in terms of objects so much. We'll have some nice methods and they will all kind of read like English. So to pull a recent example that I worked on, I might say something like expect this policy object method to conform to this truth table. STEPHANIE: That's a really interesting example. It actually kind of sounds like it hits the sweet spot of what you were describing earlier in the sense that it has a really nice DSL, but also, you can create your own objects, and that has an interface that you can implement. And yes, have your cake and eat it too. [laughs] But the idea that then you're kind of converting it back to the DSL because that is just what we know, and it has become so normalized. I was talking earlier about okay; when is a DSL worthwhile? When is the use case a good reason to implement it? And especially for gems that I think that are really popular that we as a Ruby community have collectively used most of the time on our projects because we have oftentimes a lot of the same problems that we're solving. It seems like this has become its own shared language, right? JOËL: Yeah, there are definitely some DSLs that we all end up learning because they're just so prominent in the Ruby community, even Rails itself ships with several built-in DSLs. STEPHANIE: Yeah, absolutely. FactoryBot is another one, too. It is a gem by thoughtbot. And actually, in preparation to talk about DSLs with you today, I scoured our blog and found a really great blog post, "Writing a Domain-Specific Language in Ruby" by Gabe Berke-Williams. And it is basically like, here's how to write something like FactoryBot and creating your own little mini Ruby DSL for something that would be very similar to what FactoryBot does for fixtures. JOËL: That's a great resource, and we'll make sure to link that in the show notes. We've been talking about some of the limitations of DSLs or some aspects of them maybe that we personally don't like. What are maybe examples of DSLs that you do enjoy working with? STEPHANIE: Yeah, I have an example for this one. I really enjoy using Capybara's DSL for acceptance testing. I did have to go down the route of writing some custom selectors for...I just had some HTML elements within kind of a complicated table and was trying to figure out how to write some selectors so that I could write the test as if it were in, you know, quote, unquote, "plain English" like, within this table, expect some value. And that was an interesting journey. But I think that it really helped me have a better understanding of accessibility of just the underlying building blocks of the page that I was working with. And, yeah, I really appreciate being able to read those tests from a user perspective and kind of know exactly what they're doing when they're interacting with this virtual browser without having to run it in headful mode and see it for myself. JOËL: It's always great when a DSL can give you that experience of abstracting enough to where it makes the code delightful to work with while also not having too high a cost to learn or being too restrictive in what it allows you to do. Would you make a difference between something that's a DSL versus maybe just code that's written at a higher level of abstraction? So maybe to get back to your example with Capybara, it's really nice to have these nice custom matchers and all of these things to work with HTML pages. If I'm writing, let's say, a helper method at the bottom of a test, I don't think that feels quite like it's a DSL yet. But it's definitely a higher level than specifying CSS selectors. So would you make a difference between those two things? STEPHANIE: That's a good question. I think it's one of those you know it when you see it kind of questions because it just depends on the amount of abstraction, like you mentioned, and maybe even metaprogramming. That takes something from the core language to morph into what you could qualify as a separate language. What do you think about this? JOËL: Yeah, part of me almost wonders if this exists kind of on a continuum, and the boundary might be a little bit fuzzy. I think there might be some other qualifications that come with it as well. Even though DSLs are typically higher-level helpers, it's usually more than just that. There are also sort of slightly different semantics in the way that you would tend to use them to the point where while they may be just Ruby methods, we don't use them like Ruby methods, and even to the point that we don't think of them as Ruby methods. To go back to that article you mentioned from Jason, where just reminding people, hey, if you put params on this, all of a sudden, it helps you remember, oh, it's just a Ruby method instead of being like, oh, this is a language keyword or something. STEPHANIE: Yeah, I wonder if there's also something to the idea of domain specificity where it should be self-service within the domain that you're working. And then it has limitations once you are trying to do something separate from the domain. JOËL: Right, it's an element of focus to this. And I think it's probably also a language is not just one helper; it's a collection typically. So it's probably a series of high-level helpers, potentially. They might not be methods, even though that is ultimately one of the primary interfaces we use to run code in Ruby. So it's a collection of methods that are high-level, but the collection itself is focused. And oftentimes, they're meant to be used in a way where it's not just a traditional method call. STEPHANIE: Right. There's some amount of you bringing to the table your own use case in how you use those methods. JOËL: Yeah, so it might be mimicking a language keyword. It might be mimicking the idea of a configuration. We see that a little bit with ActiveRecord and some of the, let's say, the association and validation APIs. Those kind of feel like, yes, they're embedded in a class, but they feel like either keywords or even just straight-up configuration where you set key-value pairs of things to configure how a particular class is going to work. STEPHANIE: Yeah, that's true for a lot of things in Rails, too, if we're talking about routes and initializers as well. JOËL: So I've complained about some things I don't like about DSLs. I really like the routing DSL in Rails. STEPHANIE: Why is that? JOËL: I think it's very compact and readable. And that's an element that's really nice about DSLs is that it can make things feel very readable and, oftentimes, we read code more often than we write it. And routes have...I was going to say fewer edge cases, but I have seen some really gnarly route files that are pretty awful to work with, especially if you're mostly writing RESTful controllers, and I would recommend that people do. It's really nice to just be able to skim through a route file and be like, oh, these are the resources in my app and the actions I can do on each resource. And here are the ones that are nested. STEPHANIE: Yeah, it almost sounds like a DSL can provide guardrails towards the recommended way of tackling that particular domain. The routes DSL really discourages you from doing anything too complicated because they are encouraging you to follow the Rails convention. And so I think that goes back to the specificity piece of if you've written a DSL, it's because you've thought very deeply about this particular domain and how common problems show up and how you would want people to be empowered by the language rather than inhibited by it. JOËL: I think, thinking more about that, the word that comes to mind is declarative. When you read code that's written with DSLs, typically, it's very declarative. It's more just describing a thing as opposed to either procedural, a series of commands to do, or even OO, where you're composing objects and sending messages to each other. And so problems that lend themselves to being implemented through more descriptive and declarative approaches probably are really good candidates for a DSL. STEPHANIE: Yeah, I like that a lot because when we talk about domains, we're not necessarily talking about a business domain, which is kind of the other way that some folks think about that word. We're talking about a problem space. And the idea of the language being declarative to describe the problem space makes a lot of sense to me because you want it to be flexible enough for different use cases but all within the idea of testing or browser navigation or whatever. JOËL: Yeah. I feel like there's a lot of... there are probably more problems that can be converted to declarative solutions than might initially kind of strike you. Sometimes the problem isn't quite as bounded. And so when you want customizations that are not supported by your DSL, then it kind of falls apart. So I think a classic situation that might feel like something declarative is authorization. Authorization are a series of rules for who can access what, and it would seem like this is a great case for a DSL. Wouldn't it be great to have just one file you can just kind of skim, and we can just see all of the access rules? Access rules that are basically asking to be done declaratively. And we have gems like that. The original CanCan gem and then the successor CanCanCan are trying to follow that approach. Have you used either of those gems? STEPHANIE: I did use the CanCanCan gem a while ago. JOËL: What was your experience with that style of authorization? STEPHANIE: It has been a while but I do remember having to check that original file of like all the different authorizations kind of repeatedly coming back to it to remember, okay, for this rule, what should be allowed to happen here? JOËL: So I think that's definitely one of the benefits is that you have all of your rules stored in one place, and you can kind of scan through the list. My experience, though, is that in practice, it often kind of balloons up and has all of these edge cases in it. And in some earlier versions, I don't know if that's still a problem today, it could even be difficult to accomplish certain things. If you're going to say that access to this particular object depends not on properties of that object itself but on some custom join or association or something like that, that could be really clunky to do or sometimes impossible depending on how esoteric it is or if there's some really complex custom logic to do. And once you're doing something like that, you don't really want to have that logic in your...in this case, it would be the abilities file but inside because that's not really something you express via the DSL anymore. Now you're dropping into OO or procedural world. STEPHANIE: Right. It seems a bit far removed from where we do actually care about the different abilities, especially for one-off cases. JOËL: That is interesting because I feel like there's a bit of a read-versus write-situation happening there as well. It's particularly nice to have, I think, everything in one abilities file for reading and for auditing. I've definitely been in code where there's like three or four ways to authorize, and they're all being used inconsistently, and that's not nice at all. On the other hand, it can be hard with DSL sometimes to customize or to go beyond the rules that are built in. In the case of authorization, you've effectively built a little mini-rules engine. And if you don't have a good way for people to add custom rules without just embedding procedural code into your abilities file, it's going to quickly get out of hand. STEPHANIE: Yeah, that makes sense. On the topic of authorization, you did mention an example earlier when you were writing a policy object. JOËL: I've generally found that that's been my go-to pattern for authorization. I enjoy the Pundit gem that provides some kind of light scaffolding around working with policy objects, but it's a general pattern, and you can absolutely write your own. You don't need a gem for that. Now we're definitely not in the DSL world. We're not doing this declaratively. We're leaning very heavily on OO and saying we're just going to create objects. They talk to each other. They can do anything that any Ruby object can do and as simple or as complex as they need to be. So you have the full power of Ruby and all the patterns that you're used to using. The downside is it is a little bit harder to read and to kind of just audit what's happening in terms of permission because there's no high-level overview anymore. Now you've just got to look through a bunch of classes. So maybe that's the trade-off, flexibility, extensibility versus more declarative style and easy overview. STEPHANIE: That makes a lot of sense because we were talking earlier about guardrails. And because those boundaries do exist, that might not give us the flexibility we want compared to just writing regular Ruby objects. But yeah, we do get the benefit of, like you said, auditing, and at least if we don't try to do some really gnarly, custom stuff, [laughs] something that's easier to read and comprehend. JOËL: And, again, maybe that's where in the best of both worlds situation, you say, hey, I'm creating some form of rules engine, whether it's for describing routes, or authorization, permissions, or users can build custom business rules for a product or something like that. And it's all object-based under the hood. And then, we provide a DSL to make it nice to work with these rules. If a programmer using our gem wants to write a custom rule that just really extends what the ones we shipped can do, allow them to do that via the object API. We have all the objects available to you that underlie the DSL. Add more rules yourself. And then maybe those can be plugged back into the DSL like we saw with the RSpec and custom matchers. Or maybe you have to say, okay, if I have a custom rule object, now I have to just stay in the object space. And I think both of those solutions are okay. But now you've sort of kept those two worlds separate and still allowed people to extend. STEPHANIE: I like that as contributing to the language because language is never static. It changes over time. And that's a way that people can continue to evolve a language that may have been originally written at a certain time and place. JOËL: Moving on from DSLs, we got some listener feedback recently from James, who was listening to our episode on discrete math. And James really appreciated the episode and wanted to share a resource with us. This is the book "Discrete Math and Functional Programming" by Thomas VanDrunen. It's an introduction to discrete math as a theoretical concept taught side by side with the very practical aspect of learning to use the language standard ML, and both of those factor into each other. So you're kind of learning a little bit of theory and some practice, at the same time, getting to implement some discrete math concepts in standard ML to get a feel for them. Yeah, I've not read this book, but I love the concept of pairing a theoretical piece and a practical piece. So I'll drop a link to it in the show notes as well. Thank you, James. STEPHANIE: Yeah, thanks, James. And I guess this is just a little reminder that if our listeners have any feedback or questions they want to write in about, you can reach us at hosts@bikeshed.fm. JOËL: On that note. Shall we wrap up? STEPHANIE: Let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeee!!!!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
It's gardening season! Stephanie swaps seeds with friends and talks about her Chicago garden. Joël recently started experimenting with a dedicated bookmark manager. They discuss the aspirational (and sometimes dogmatic) sides of TDD and explore when to test: first or after. How does that affect the tests? How does that affect the code? How does that affect workflow? Are you a "better" programmer because you 100% TDD? This episode is brought to you by Airbrake (https://airbrake.io/?utm_campaign=Q3_2022%3A%20Bike%20Shed%20Podcast%20Ad&utm_source=Bike%20Shed&utm_medium=website). Visit Frictionless error monitoring and performance insight for your app stack. Cassidy William's Productivity tools (https://dev.to/cassidoo/the-productivity-apps-i-use-in-2023-3m8l) raindrop.io Bookmark Manager (https://raindrop.io/) Simplifying Tests by Extracting Side-Effects (https://thoughtbot.com/blog/simplify-tests-by-extracting-side-effects) Transcript: JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. STEPHANIE: And I'm Stephanie Minn. And together, we're here to share a bit of what we've learned along the way. JOËL: So, Stephanie, what is new in your world? STEPHANIE: It's gardening season here in Chicago. So right now, it is like mid-April as we're recording this, and we are just starting to get some warm weather. And this is usually the time that I do my garden planning for the season. And the other week, I went over to a friend's place, and we did a bit of a seed share. So we just each have collected fruit and vegetable seeds and herbs and all that. And a really fun way to collect more things to grow is to share with your friends. Seeds are super cheap, but I feel like you could just have like an infinite amount for all of the things that you might want to grow. And so it's really nice to be able to, yes, spread that gardening love around and share with your friends. JOËL: I'm imagining something like people trading collectible trading cards but the plant version. STEPHANIE: Yeah, exactly. The fun thing that we did, my friend and I, because, you know, you usually get a little envelope with between 10 and 50 or more seeds, and they're super tiny. Some of them are really teeny tiny, like with broccoli, for example, it's like I can't even explain. It's less than a millimeter, I swear. It's very easy to just lose them, so you want to keep them contained. But because we are sharing, we don't have a second envelope for the other person to take home with them. And so we actually made our own little envelopes with some origami paper that she had. And we folded it and stapled it and made it very cute. And so I came home with a bunch of these very adorable handmade envelopes with all of my new seeds. JOËL: Are you mostly doing vegetables, or are these flowers? STEPHANIE: Yeah, so we mostly focus on vegetables for our garden. And we do like to sprinkle some flower seeds in our yard. But that is more just like throw some seeds out there, and whatever happens to them happens. But with the vegetables, we put a little bit more effort because we usually try to have a good yield. So in past years, that has meant starting seeds indoors because, in Chicago, we have a shorter growing season than some warmer climate places. And the late summer vegetables like tomatoes, peppers those usually take a little bit longer. So if you want to get a good yield, you might want to start them inside a little early before it's warm enough for them to go outside. JOËL: So, do you have a garden plot out in your yard, or do you have a community garden plot? How does that work? STEPHANIE: I am really grateful to have a bit of backyard space. And we have three raised beds that we built that cover...I think each one is 3 feet by 10 feet, so quite a good amount of space. Yeah, we're able to grow a lot of food. Our highlights include shishito peppers. That's one that I really like to grow myself a lot because I usually don't see them in stores as frequently. We grow really great eggplants. Tomatoes, obviously, is a pretty popular beginner-friendly vegetable plant. And we like to grow a lot because then we can process it all and can some of it so we can have nice tomato sauce that's homegrown year round. JOËL: Hmm, sounds delicious. Do you experiment with the different varieties? STEPHANIE: We do. That's also a way that the seed sharing is really helpful because maybe I'll get some varieties of certain vegetables like cucumbers or whatever, but maybe my friend has a different kind. And I think we try to do a mix of growing the varieties that we know we like and then experimenting with some ones that are new to us. JOËL: It's hard to beat fresh vegetables in the summer. STEPHANIE: Yeah. I'm very excited, especially because during the fall and winter seasons here in Chicago, our local food is a little less exciting. It still can be good, but it's been a lot of root vegetables and the like when we try to eat seasonally in the other season. So I'm really looking forward to stuff that's just juicy and fresh, and it's just one of my biggest joys during the summer. What about you, Joël, what's new in your world? JOËL: I've recently started experimenting with a dedicated bookmark manager. This is not because I have been to too many bookstores and have all the free bookmarks they give you. These are the digital bookmarks to websites, and I've been really bad at managing those. I mostly just memorize the keywords I need to Google to get access to that website, which is a terrible way of doing things. And then I've got a mix of a few different browsers, which I don't sync, and have a couple of bookmarks. I use a little bit of Pocket, which is a tool by Mozilla. It's all right, but the search capabilities are not very good. So sometimes I'll know it's in there, but I can't find it. STEPHANIE: I'm so glad you brought up this topic because I am in a similar boat where I read a lot of things on the internet and have just thrown them all into my top-level bookmarks hierarchy. And that has not really been working for me, either. So I'm really curious to find out how you've been solving this problem. JOËL: So recently, I volunteered to be a mentor for first-time speakers at the upcoming RailsConf in Atlanta. And someone was asking me about designing slides, and we were talking a little bit about when should you use maybe a bulleted list on a slide versus when there are other options available. I knew that I had read years ago a fantastic resource on slide design. But try as I could, I could not Google this and get the page that I was looking for. This was shared to me by somebody else as part of a conference preparation group years ago, and so I reached out to this person. I was like, "Hey, so do you happen to remember that link you shared with me five years ago?" And this person says, "I do remember it. I don't have the link either." STEPHANIE: I've literally been in this exact same situation where I remembered that there was an article that I read, and I remembered exactly who shared it with me or who I talked about it with, and when I couldn't find it, trying to reach out to them and also not being able to find it through them. JOËL: So the story ends well because I was able to log into an old Slack group... STEPHANIE: Wow. JOËL: That had been created for the speakers at this conference and dig through the history. And luckily, I still had access to the group. I was still in that private channel for the speakers. And I found the link, and I was able to share it with others. So that was great. But then I started thinking; I can't keep living this way. I need something better. STEPHANIE: It's true. Even though we are expert Googlers as developers, sometimes the search just doesn't get you the thing you're looking for. JOËL: So, about this time, I'm scrolling Twitter as one does. And I saw a tweet from Cassidy Williams talking about some of the productivity tools that she's been using this year did a longer article about it. And I started reading it, and a tool that she mentioned there is Raindrop.io, which is an all-in-one bookmark manager. And I'm like, oh, that is exactly, I think, the missing piece of technology in my life right now. So I went up and signed up for it, and so far, it's been pretty good. I'm experimenting with it. But I've consolidated a lot of the links that were in my head or in some of these other places, put it in there, categorized them a little bit, tagged them. And hopefully, this becomes a better way so that when I want to reference a link for someone else either in a conversation or as a resource or even for myself, maybe when I'm writing an article, I'm like, oh, I know I read something that would act as a good resource here. I can go to Raindrop and get that article without any of these other shenanigans I had to do this time. STEPHANIE: Amazing. What is special about Raindrop as opposed to just your native browser bookmark capabilities? JOËL: It has some deeper structuring capabilities in terms of not everything has to be hierarchical. It has tags as well as categories. And I think most importantly, for me, it has search, which seems to be pretty good at surfacing things. It also has some somewhat smart capabilities where it will automatically figure out if the thing that you've linked is an article, or a document, or a video, something like that. So you can filter by these inferred types as well. It has the ability to sync across devices, which browsers can do if you're signed up for them. STEPHANIE: Nice. I like that it has that search functionality that you mentioned because I think I'm definitely in the boat of just scrolling through all of my untagged, unorganized bookmarks. And it's really tough to find what I'm looking for, especially if the meta title also doesn't quite tell me exactly the keywords that I'm needing to be scanning for in that moment. So I will definitely have to give it a try. JOËL: I believe you can get full-text search if you pay for the premium version (I'm currently trying the free version.), which in theory, could mean that it searches the contents of the article. It's not clear with that. But I do know they save a snapshot of the text of the article. STEPHANIE: That's really interesting because then it's almost like a search engine but scoped to the things that you have saved. JOËL: Yes. STEPHANIE: Nice. JOËL: I'll see how that goes, and maybe six months from now, I can talk a little bit about what the experience has been using that. STEPHANIE: Yeah, six months from now, you can tell us all about how you have no issues or qualms with how you've been managing bookmarks because everything is working perfectly well for you. [laughs] JOËL: JK, I've dropped this whole bookmark thing. STEPHANIE: That's true. That's also the flip side of trying out a new tool, [laughs], isn't it? MID-ROLL AD: Debugging errors can be a developer's worst nightmare...but it doesn't have to be. Airbrake is an award-winning error monitoring, performance, and deployment tracking tool created by developers for developers that can actually help cut your debugging time in half. So why do developers love Airbrake? It has all of the information that web developers need to monitor their application - including error management, performance insights, and deploy tracking! Airbrake's debugging tool catches all of your project errors, intelligently groups them, and points you to the issue in the code so you can quickly fix the bug before customers are impacted. In addition to stellar error monitoring, Airbrake's lightweight APM helps developers to track the performance and availability of their application through metrics like HTTP requests, response times, error occurrences, and user satisfaction. Finally, Airbrake Deploy Tracking helps developers track trends, fix bad deploys, and improve code quality. Since 2008, Airbrake has been a staple in the Ruby community and has grown to cover all major programming languages. Airbrake seamlessly integrates with your favorite apps to include modern features like single sign-on and SDK-based installation. From testing to production, Airbrake notifiers have your back. Your time is valuable, so why waste it combing through logs, waiting for user reports, or retrofitting other tools to monitor your application? You literally have nothing to lose. Head on over to airbrake.io/try/bikeshed to create your FREE developer account today! STEPHANIE: So our topic for today is something that we've had in our topic backlog for a while, and I'm excited to talk about it. It's TDD, which I think is a very well-known, potentially controversial topic of discussion in the world of software development. And specifically, we wanted to talk about when TDD is useful and when you actually might also have some value in writing tests afterwards. And in preparation for this topic today, I actually have been TDDing most of my client work this week. JOËL: What? You're telling me you don't TDD 100% of the time? Are you even a real developer? STEPHANIE: I am a real developer, and I do not TDD 100% of the time. I'm just going to say it. It's on record. JOËL: You know what? Me too. STEPHANIE: Wow, I'm glad we could clear the air on that one. [laughs] JOËL: What percent of the time would you say that you do TDD? In this case, test first as opposed to maybe testing after you've written the code or maybe not testing at all. STEPHANIE: Hmm, that's an interesting question. A part of me wants to answer it in my ideal workflow terms. But I think that is less interesting than reality, which is I will usually at least try to test first if I'm feeling like I am up for it. So maybe the percentage is, I don't know, I really couldn't tell you, but I'm just going to throw out 40% of the time [laughs] because that seems pretty, I don't know, reasonable. Sometimes you wake up, and you're just like, I'm not going to do it today. [laughs] And other days, you wake up, and you're like, you know? It sounds like a fun exercise to do for this particular feature. So yeah, if I TDD 40% of the time, then I think maybe I write tests after another 40% or 50%. And then [laughs] I'm hesitant to say this on the air, but sometimes you code, and you don't write tests for it and would not recommend it for the majority of your work. But I'm just going to be real here that sometimes it happens. JOËL: It's always a trade-off in terms of the work you put in versus the value you're getting out of it. And sometimes, you get very little value out of a test. STEPHANIE: Yeah, that's real. It totally depends on what you're doing. JOËL: I think one thing that's interesting for us, because we're consultants, so we move from one project to another, is that some projects are set up in a way that they're very test friendly. It's easy to have a testing workflow with them. And then others are just incredibly painful to test because of the way the system has been architected. And I think a TDD purist would then tell us that this is a symptom of high coupling or other architectural problems; that's probably true. But also, you don't have time to re-architect the entire system, and so then it becomes a question of trade-offs. Can I test some things easily today? Can I refactor a few things that will make this local change somewhat easier to test? And then, where is it not worth the effort to make something testable? STEPHANIE: Yeah, I've definitely struggled with that, where a part of me wanted to test something very thoroughly or even do test-driven development and then ran into some obstacles along the way and having to be realistic about that effort. The other thing I was referring to around it depending is also the actual code you're working on. So maybe if you're just writing a script or something to automate some dev workflow, it's okay for that not to be tested. And I also do think that the decision to TDD is very dependent on whether you are writing net new code, or refactoring, or having to deal with legacy code. JOËL: That definitely makes a difference. For me, when I'm refactoring in the purest sense, changing structure without changing behavior, in theory, I should not be writing tests for that because there should already be existing tests, and I'm not changing behaviors. So the test suite should prove that my changes did not change behavior. In practice, oftentimes, there is not the coverage that needs to be there. I don't know about you; I feel like I often don't trust the code enough, where I'm a little bit scared to do a refactor if there isn't test coverage. How about you? STEPHANIE: I've been running into that issue a lot on my current client project where I've been making an intentional effort to add test coverage before I make any changes because that forces me to really understand how things work because either I read a piece of code and I just can't tell at all. Or I learn later on that I thought I understood something based on the class or the method names, but it turns out that there was actually some nuance in there or side effects or what have you that belied my understanding [laughs] of what it was doing. And after a few times of that lack of trust that you talked about popping up, I was like, okay, I think, at least for me, the way that I can feel good about the work that I'm doing is to set myself up for success in that way. JOËL: Do you ever find that the code that you write in a test-driven approach tends to end up different than code that you might write with a test-after approach? STEPHANIE: Yeah, I think this can actually be answered at a few different levels but let me start with talking about how I like to practice TDD. If I'm given a user story, I usually try to work outside in. So I will write a feature or acceptance test and that involves testing how the user would interact with our application. At that point, I will usually go with the most naive implementation to get the test passing, and so it probably won't look pretty. In a recent case, I was adding a new parameter to a controller, and I just put everything in the controller to get the test green. [laughs] And then, at that point, is when I gave that code a second pass and looked for areas to extract where I could. JOËL: That refactor step and the red, green refactor cycle is really important. STEPHANIE: Yeah, absolutely. I think that is where I find TDD to be the most valuable from that higher-level perspective. And I know that there are different schools of thought on this. But that helps ensure that at least I have written the code to make the feature work the way that I was hoping. And I use TDD less for driving design decisions just because I like to have something to react to that is helpful for me rather than having a blank slate of, okay, let me write a test with an idea about how an object's interface will look. And so that's what works for me. So I do think it's kind of a mix of like from an acceptance test level; I am at least writing code that I know works, but the shape of the code for me is less determined by how I test. JOËL: So when you're looking at code that you've written six months down the line, you generally can't tell the difference whether it was test-driven or written first and tested after. STEPHANIE: That sounds right. That's just how my process works. In fact, I think recently we, to go on a quick tangent, we talked about writing conference talks, and I think I even mentioned for me the process is looking at the thing and then revising. And I think that the design driving element of TDD that a lot of people like is a bit less effective for me personally. JOËL: Hmm. Would you say that TDD does not impact the shape of the code that you end up creating in response to the tests? Or when you're talking about design, are you mostly thinking in terms of the interface that you would have in the test itself, like, what arguments the constructor takes or things like that? STEPHANIE: I think I was talking more about the latter, the interface, the construction arguments. When I do test afterwards, I also will notice the way the setup of my test how that is feeling. And if it is feeling a bit unwieldy or is a bit complicated, that will cue me to maybe take another pass at the code itself. So that's actually one way that testing after can signal to me a way that I might want to change my code. JOËL: Okay, so you're getting some of those pressures that you get from testing, but you respond to them in a like second path? STEPHANIE: Yeah, I think so. I'm curious how you TDD and whether you notice changes in how your code looks. JOËL: I think there are a couple of things that TDD does in my workflow that are really nice. One is it keeps me focused in terms of getting the work done because you're just following from one failure to another. It also keeps me focused in terms of scope. It's really easy for my engineering brain to be like, oh, we could totally do this thing and all that, and it's like, no, that's not needed to solve the problem at hand. Because in TDD, you try the smallest solution that will solve your problem, and then you will refactor it to make it maybe nicer to work with. But you try not to add new behavior that's not required in order to pass the test, and that can be a really helpful forcing function for me. STEPHANIE: That's interesting because I was just thinking about how sometimes, at least with the outside-in approach that I was talking about, I will find that the scope of the ticket is too big as I make changes to get the desired quality of the code that I want. Like I mentioned, the naive implementation, like, sure, maybe everything is in a controller, but as soon as I'm starting to do that second pass, and I want to maybe change another class and to make it work for my needs, I will notice it start to sprawl a little bit. And that is usually a signal to me that, like, oh, maybe what I need first is just refactoring the objects that I'm hoping to use to get the desired implementation. And that ends up being a separate PR that I do first to then set myself up for making the change. JOËL: The classic make the change easy before you then go and make the easy change. STEPHANIE: Right. But that does mean that that initial feature test that I wrote won't ever be green. So I do have to kind of like back out of making that change and just be like, okay, today is not the day [laughs] that I'm going to get this feature working. JOËL: There are some times where I'm in a situation like that, and I will kind of recognize, oh, there's a refactor step that's happening right now as a sort of subtask. And so, I will make that refactor change that I need to and then commit only those files that were a part of that refactor and may be included as part of the PR with the feature change or maybe push it up and make it its own PR. But depending on what the refactor is, oftentimes, I can kind of do it sort of all more or less continuously but decide once I've done that refactor step, okay, commit time but only those files for the smaller set of changes, and then keep moving with that outside-in approach. One thing I have noticed about the style of code that I tend to produce when I TDD versus when I don't is how I will tend to decouple things. And so because coupled code is really annoying to test in isolation, TDD sort of forces me to do more dependency injection, passing objects to others. It will often force me or maybe not force me, but it gives me that wholesome pressure to maybe separate HTTP requests from more of the business logic in my code, which otherwise I might completely intermix because it's just so convenient. Even certain things like class methods, I might tend to overuse them or use them more if I'm not test driving than if I were. STEPHANIE: When you talk about coupling, I'm curious, do you end up mocking a lot in the tests that you are writing to drive your development? JOËL: No, but if I'm testing after, I probably will. Mocking, I think, is a sign of coupling generally. In tests where you're just passing objects to each other, generally, you can get away with passing in a test double or something, whereas if you're hard-coding dependencies, you often have to mock. STEPHANIE: Got it. That makes a lot more sense now. I think that does require a bit of thought upfront about what kinds of objects you might need and what they would provide for you in the thing that you're testing. JOËL: Yes. There's definitely a phase where let's say; I'm testing some kind of third-party integration; I'm just kind of trying to do it all in one object that has a mix of business logic and some HTTP request stuff. It gets really annoying as we're adding...maybe the first feature is okay. I use WebMock, and I stub out a request, and it's good. And then the second one, I feel like I'm kind of duplicating that. And then the third one, I've got to deal with retries. So now I've got to go back to the first one and add some two or three WebMocks because now we've got exponential backoff code that's happening here. And this new feature broke the old tests. And it just becomes this really annoying thing to do. And then I might start thinking, okay, how do I separate these two things? I have one place where I test the HTTP logic, the exponential backoff, the what to do if I get a 404 from the API. And then, separately, I can just have the business logic and test all of those branches there without having to touch any of the HTTP stuff. I think you could get there from a few different paths. So you could get there by sort of following a lot of classic design principles, things like SOLID, because they kind of converge on that general idea as well. You could even get there if you took more of a functional programming approach where you are really good at separating side-effectful code from, I'm going to use the term loosely here, pure functions. I've heard some people make the distinction between IO versus non-IO in code and how that affects the types of tests that you write for them. And separating those two is a thing that you might do, even if you weren't writing tests at all, if that's a design principle that you know to follow. STEPHANIE: Yeah, that's a great point. I was thinking, as you were talking about your approach for handling that potential feature with talking to a third party, that I've heard that particular task or problem in software development used as an example for a lot of those different techniques or strategies that you mentioned. And I suppose TDD really is just a tool, and it doesn't replace your experience or intuition. And earlier, when we were talking about times that you don't do TDD, I will have to say that if I am doing something that I've done many times before, I feel confident enough that I don't need to lean on that red, green refactor cycle. At that point, it's more muscle memory. And maybe I do forget a step along the way, but I have the experience to know how to debug that or to see the error and know exactly what it was that I did wrong. And in that case, I am tapping into something different than using TDD. JOËL: I think definitely, for a lot of things now, there are patterns that I have learned where even if I weren't TDDing, I might do a third-party integration using this pattern because I've done it via TDD enough to know that this is a structure that I find works very well in terms of the coupling of things. And then maybe if I want to fill in some tests afterwards, then I'll thank my past self that I'm using a pattern that plays nicely with that. One thing that I do notice happens sometimes is that when people add tests after the fact, they will add tests that are green but that don't necessarily fail if the code breaks. Have you ever seen that? STEPHANIE: I have seen that before. In fact, I just saw it recently where we had a false positive test. And I made a change expecting the test to fail, and it didn't, which is not great because the value that tests have are when they fail, you want to be alerted when something goes wrong. Just because they're green doesn't mean that everything works. It just means that they didn't detect a problem. And in this particular case, I don't know if the developer who wrote this test had TDDed or not. But I did notice that in the test, we were mocking a method, and that ended up being the cause of the false positive. JOËL: I'm always a little bit skeptical of mocks because I feel like I've seen so many either brittle tests or tests that will succeed all the time come out of mocks. I don't know if you've ever heard the term tautological test or a test that is a tautology. STEPHANIE: No, I haven't. What does that mean? JOËL: In its sort of most basic sense, it's a test that is always green no matter what the output is. Some people think of it more in terms of self-referential tests, like, oh, a thing equals itself, which, yes, it does, and those tend to be always green. But it's not always self-referential. It can be some other subtle ways. Typically this happens when mocking or specifically if you mock the system under test. It's very easy to write a test that is now going to always be green, no matter how the code changes. A fun fact about the word tautology is it comes from discrete math, which is the topic of my RailsConf talk. If you write out a truth table that shows all the possible inputs and whether or not something will be true or false, depending on what the inputs are, the output column is all true in a tautology, which tells you that no matter what the inputs are, you're going to get true out of that method or function or equation. And so, if this was a Boolean expression in Ruby, you could replace that by hardcoding true and get the same result. STEPHANIE: Yeah, that's what I was imagining, a function that just returns true. [laughs] JOËL: And that's effectively what you can accidentally write when you're creating a test that is a tautological test is one where you could have just replaced the entire thing with expect true to be true, and it would have the same effect. And, like you said, tests only have value when they fail. And a test that never fails has no value. So TDD has this red, green refactor cycle. I feel like you could probably come up with a cute slogan like that for a testing-after style. So maybe I guess you'd start off you write some code, then you write a test that theoretically passes for it. So you start green, but then you want to make sure you see that test fail, so you got to go red and then comment out the code or something. Then comment it back in to see that it goes back to green to make sure that not only does this test fail when the code is broken but also that bringing this test back is what makes it pass, which is an important distinction. So maybe it's a green, red, green, and then maybe refactor. Because one thing that I admired in the style that you were talking about earlier is that even when you test after, you include a refactor step. The test at the end is not the final step in your workflow. STEPHANIE: Yeah, that's a really good point. When you said green, red, green, I was thinking of a Christmas garland [laughs] or something like that. But yeah, I do think that stuff gets skipped sometimes. If you are testing after, you're backfilling tests for code you wrote, and at that point, you think you know how it will work, and so you're writing your tests kind of colored with that in mind. I like the injecting commenting something out or changing an input or something that you know should make the test fail, just so that you can confirm that you didn't just write a test that expects true to equal true or give you a false positive like that, then go back to green. And as you were saying that, it did make me think like, oh, well, that's like a whole extra step as opposed to TDD where we do just have red, green refactor. We don't have that extra step. But I think the effort is just like put in at a different point in time. JOËL: Agreed. It's important that you see the code fail and that you see it pass after the change. The order has changed a little bit, but those two kinds of core elements are present. Kind of by default, you have no choice when you're doing TDD. You have the ability to skip that if you're testing after, but ideally, you incorporate those in a robust test after workflow as well. STEPHANIE: Yeah. And I know I mentioned times when I've done something enough or used a pattern enough that maybe I'll just go ahead and implement it and then backfill with tests. And I also recognize that in those moments, I could have done something wrong, that there is some amount of wanting to check that the test failed. And I imagine there is some kind of balance to achieve there between the speed that you get by having that experience and knowing the direction you want to take things and applying a pattern that you've done a lot with being like, oh, we're all human, and sometimes we make mistakes. JOËL: In a situation where you feel like you're coding something that you've coded up 100 times before, you're very familiar with this. Do you find that a test after workflow is faster for you? STEPHANIE: Hmm, that's an interesting question. JOËL: Because I think that's often a motivation. It's like, I don't want to bother, like, I just have the idea. I know what to do. Let me just write that code and get it done. STEPHANIE: I think if I were introducing a new route or controller action or whatever, I don't need to go through the cycle of writing a test and it failing because I haven't added the action to the controller yet. It's like I know that that is the next logical step, and so maybe I might skip it there. But if I'm at the point where I'm working with business or domain logic, I think that's where is the value of test writing first because it's like, I passed the framework and passed my tools. And now, I'm working at working through the logic of the business problem itself. JOËL: So you're working in maybe slightly larger iterations of that red, green refactor cycle. STEPHANIE: Yeah, that's a good way to describe it. JOËL: I was recently working on a gem and tried to TDD it from scratch and went with micro iterations. And it was actually really fun, and there was a flow to it. And this is a greenfield side project. And it helped me stay focused. I think it did give me a decent design. I really enjoyed it. STEPHANIE: Nice. Was there something satisfying about seeing that green each time and kind of doing that bit of mechanical labor? And I can see how that can feel almost meditative. JOËL: Yes. And I think also because this was a problem that I didn't fully know how I was going to solve, TDD helped really focus me on solving sub-parts of that problem, things that I can hold in my head and solve in a minimalistic way and then iterate on. STEPHANIE: I like that a lot. You were using that technique, and that really helped for the task at hand, which was, in this case, a bit smaller in scope. I think the way you and I have been talking about TDD has been very realistic and very reasonable. And I'm curious what you think about people who kind of use it as the pinnacle of how you should write code. JOËL: I think that's really interesting because TDD is a really wonderful technique, and I wish more people used it. But it's kind of taken on a mystique of its own where if you do TDD or claim to do TDD 100% of the time, now, all of a sudden, you've put yourself on another level. And I think people even who choose for pragmatic reasons not to TDD all the time maybe feel a little bit of guilt or at least feel the need to explain themselves to other people to say, "Hey, I didn't TDD this here. Well, let me explain to you why that's okay, and I'm not a bad programmer." STEPHANIE: Yeah, I think we even alluded a little bit to that earlier in the show, and I could hear my hesitancy to be like, oh, I guess I'm going to say this and have all these people hear it. But I think that's a good point that it's okay for you not to do it 100% of the time. That doesn't make you any less of a programmer. Also, the way we've been talking about it also makes it sound like one of those things where it's like you do have to learn the rules before you can break them. And so there is value in learning it and doing it. And then you also, after having done it enough, know when you want to use it or when you don't. My advice for folks who haven't really done it before or don't quite see the value of it is just to try it and then decide for yourself. I think at the end of the day, we should all feel empowered to be able to decide how we work best. JOËL: It's also really valuable, I think, to maybe pair with someone who is really good at that and to get to see what their workflow is like. Oftentimes, there's almost a hump of getting into it where you are more productive without TDDing because you're not comfortable with the flow or with the techniques. And it takes a lot of expertise to get over that hump where maybe at the expert end of things, you are more productive with it. And on the less expert end, it just becomes a chore that takes up all of your time or ends up giving you results that aren't that great anyway. And so, how do you cross that chasm? STEPHANIE: Yeah, that's a really, really great point because, in some ways, when you first get started, it will feel slow. You are unlearning the ways that you have known to code before and trying to do it in a different way. And I really like your advice about trying to pair with someone who has expertise or has been practicing it for a long time. That was my first real introduction to it too. At this point, I had been a few years into my career and hadn't really tried it because it seemed very daunting, and seeing someone else verbalize their process and seeing their workflow was really helpful for me to get on board. JOËL: I think what I would like is for TDD to be a tool that is aspirational for a lot of people. If you're new to the technique and you've paired with somebody who's really good at it, and you see the flow that they have and be like, wow, that's really good. I would love to get that incorporated in the way that I work. Rather than a sort of measuring stick for how elite of a programmer you are. There's no sense in shaming people over the tools they use. STEPHANIE: Right. Because it should also be accessible, and if you make people feel bad about it, and then it's not accessible to folks. JOËL: On that note. Shall we wrap up? STEPHANIE: Yeah, let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeee!!!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
Joël has been working on his RailsConf talk about various aspects of discrete math useful in day-to-day work as a developer and going deep on some concepts from propositional logic and Boolean algebra, particularly DeMorgan's Laws, which explain how to negate a compound condition. Stephanie attended a meeting with a fun "Spicy Takes" topic. She gave a short talk on how frictionless technology may not be the best path forward and tried to argue in favor of more friction in our software. Together, they talk about ways they've made remote work work for them and things they'd like to try/do differently. This episode is brought to you by Airbrake (https://airbrake.io/?utm_campaign=Q3_2022%3A%20Bike%20Shed%20Podcast%20Ad&utm_source=Bike%20Shed&utm_medium=website). Visit Frictionless error monitoring and performance insight for your app stack. Taskmaster - Do Not Avoid Not Making the Bell Not Ring (https://www.youtube.com/watch?v=8iEnaOKGOFw) The Dark Side of Frictionless Technology (https://newsletters.theatlantic.com/galaxy-brain/6328fa97bcbd490021b314da/personal-tech-obsolete-user-experience/) Is Tech Too Easy to Use? (https://www.nytimes.com/2018/12/12/technology/tech-friction-frictionless.html) How to Do Nothing by Jenny Odell (https://www.penguinrandomhouse.com/books/600671/how-to-do-nothing-by-jenny-odell/) Rubber duck Debugging (https://rubberduckdebugging.com/) Schedule Shutdown, Complete Bike Shed episode (https://www.bikeshed.fm/310) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: I've recently got accepted to speak at RailsConf. And I've been working on my talk about various aspects of discrete math that are useful in day-to-day work as a developer and going really deep on some concepts from propositional logic and Boolean algebra, particularly the DeMorgan's Laws, which explain how to negate a compound condition. So if condition one or condition two, if you want to negate that thing as a whole, you can't just negate both of the conditions individually. You will get a totally different result, and that's a really easy mistake to make. I don't always memorize exactly what to do. But I know enough in the back of my head when it comes up on a pull request to check it out and be like, oh, there's a negating of a compound condition here. Pay closer attention. There might be a bug. STEPHANIE: So are you saying that when you negate each condition individually, you get the opposite result that you want? JOËL: It's not opposite, just different. STEPHANIE: Just different, okay. JOËL: So De Morgan's Laws tell us that if you want to negate the compound condition as a whole, you negate the individual clauses but then also have to flip the sign in the middle. So if you're trying to negate condition one and condition two, it becomes not condition one or not condition two. STEPHANIE: I see. Wow, that's confusing because you'd think that there are just two outcomes, but really there are a lot more. JOËL: Yes. STEPHANIE: And that reminds me of when we've talked about on the show combinatorial explosions, which I know is a favorite topic of yours. JOËL: Combinatorics will definitely come up in the talk as well. It's sometimes hard to hold all the possibilities in your mind. And so I'm a big fan of truth tables to visualize what's happening and to be like, oh, when I make this thing negative, now all these things flipped into false when I want them to be true and vice versa. Okay, I've got a weird inverse going on here or something like that. STEPHANIE: I have a funny thing to share with you. Joël, have you ever heard of the show "Taskmaster"? JOËL: No, I'm not familiar with this. STEPHANIE: Okay, it's a British reality competition comedy show where the contestants are usually famous British actors or comedians. And they have to do just really insane, silly tasks. And usually, one of the more iconic ones is to eat as much watermelon as you can in a minute. But they're just presented with a whole watermelon without any tools or anything [chuckles] for cutting it up. And it's just very funny and very delightful. And one of the tasks that I watched recently was a situation where they had to follow these instructions, and the instructions were to do the opposite of the following statement: "You must under no circumstances not avoid not making the bell not ring." And they had a bell right in front of them. And so they had to figure out if they were supposed to ring the bell or not ring the bell based on those instructions and within a certain time limit. If they had the math skills that you were talking about, [chuckles] perhaps they would have been able to figure it out. JOËL: I would absolutely want to write that out as a more formal logic thing. Otherwise, it becomes...you just mess with your head. You get in almost a recursive space where like, wait, not not, does that cancel? Does it stay? And yeah, it gets really messy. STEPHANIE: Yeah, it was very funny to watch them try to figure that out on the spot. And I think there's a clip of it on YouTube that we can link [laughs] for our listeners. JOËL: That's amazing. What's new in your world? STEPHANIE: So last Friday...you and I are on the same team at thoughtbot called Boost, and every two weeks, we get together as a team, and we have a meeting where anyone can propose a topic. It's just a nice space for people to see each other and hang out. And one of our co-workers hosted that meeting and he chose the topic of spicy takes and asked for volunteers to sign up and give a quick couple of minutes lightning talk on the spicy take that they had. And it was so fun. We got some takes on how REST is not the best. We got some opposing opinions about Tailwind. And I ended up giving a short, little talk on how frictionless technology may not be the best path forward and was trying to argue in favor of a little more friction in our software. JOËL: What would friction look like in this scenario? STEPHANIE: I was really interested in exploring how by making our software so easy for users we eliminate some amount of attention and mindfulness into using technology. So I think for me friction would be presenting the user with more autonomy and choice rather than making decisions on their behalf. I don't totally know what that looks like, but I do know that things like one-click ordering or autoplay those things have made me bristle a little bit in certain contexts and wondering what other options do we have available to us to provide the features we want to provide to our users but maybe not in a way that is so convenient and easy to use that we lose that aspect of knowing what we're doing with our technology. JOËL: I feel like knowing you, you've probably read a couple of articles and some books on this topic. And if I wanted to dig more into this idea of a little bit more mindfulness or introducing a little bit of friction into my software world, where would you recommend I go to read? STEPHANIE: Yeah, that's a great question. When I was preparing the talk, I referenced a few articles that I'll link in the show notes, one from The Atlantic and one from The New York Times. And I liked them because one of them presented what I was getting at, the more philosophical approach of like, what does it mean for our attention to be? And what does it mean for our technology to be too easy? And the other one had more practical use cases for security and technology misinformation and abuse. So I liked that those two things complemented each other equally. And then I also would plug a book called "How to Do Nothing: Resisting the Attention Economy" by Jenny Odell. I read that book last year and really enjoyed it. And she talks a lot about just the current technology landscape and what we, as consumers and users, can do to reframe our relationship with it. And I think that book is for people who use technology in general. But as developers, I think we are in a unique position to extend that train of thought right into the things that we develop. JOËL: You know, a place where I do appreciate friction is in the physical world. If there weren't any friction, my chair would not stay put on the ground. My fingers would not press on the keyboard. So we need friction to be able to do our jobs. So you work from home; I work from home because thoughtbot is now fully remote. How has that been for you setting up a work environment in your home? STEPHANIE: So I've actually been working from home since 2019. So about a year before the pandemic, I had moved to Chicago and was still working for a company in New York. And so that was when I started working from home, and then have just been doing that ever since. So I think I have now really figured out a setup that works for me. I've been doing it for four years now, which is pretty wild to me when I think about it. It's interesting because I actually really enjoyed going into an office. And there are parts of that that I really miss. But I think I have just gotten used to it and have a setup that works well for me. JOËL: Are there any things that you like to do for your environment to help get yourself into maybe the zone a little bit more easily? STEPHANIE: Yeah. So my workspace is a separate room from the rest of my apartment, which is also really just one big room. [laughs] It's kind of like a loft-style situation, so I don't really have doors. But I am in what we call the sunroom, and it's actually kind of like an enclosed porch with a big window and lots of plants. And it's in the back of the apartment. And so whenever I'm in this space, it's because I'm working. And I think having that separation of home and work is really helpful. Because when I step into this space, I'm like, okay, now I'm at work, and I don't have as many distractions as I would if I were working in a different space like a bedroom or the living room. JOËL: I have to say whenever you're on a video call, the plants around you are iconic. STEPHANIE: Oh, thank you. Yeah, it's been a nice conversation starter. When I'm meeting a new person, they usually comment on the plants, and I can give them a little show and tell. And that's been really nice. JOËL: I feel like a lot of people who work from home have put a lot of work into creating fun backgrounds for their video calls. Maybe they're setting up a cool bookcase behind them or plants. People like to put something behind them that will make things interesting on a video call in a way that maybe we didn't need to when it was just a conference room and in an office. STEPHANIE: Yeah, absolutely. I was just on a meeting with someone who had a big pile of tiny rubber ducks. So he was also a developer and, I guess, had just amassed this very delightful rubber duck collection, and it was just in the background. And we got to joke about it for a little bit, and that was really fun. JOËL: Are these rubber ducks meant to be used during debugging sessions? STEPHANIE: Yeah, exactly. JOËL: So I'm in a somewhat different situation from you in that I don't have a separate room to set up a home office. I've resisted doing anything in my bedroom. Like you said, it's good to have that separation. So I work more in my kind of living room-dining room space. And something that I found is really valuable for me has been movement. So say I work an hour in one part of the room, and then I switch to a different place. And it's going to be maybe a different posture. So I'm working in a solid chair table for a while, and then maybe I switch to more of an easy chair situation. That I think has been really helpful for me ergonomically during the day is just making sure that I'm not always in the same position constantly all the time but actually incorporating change in movement throughout my day. STEPHANIE: I like that a lot. I actually do also end up sitting at my dining room table sometimes for a change of scenery. It's funny because there was a while when...when I'm at my office desk, I have a standing desk. And so usually if I'm in a meeting, I would be at my desk and people would see me standing. And I think someone at some point mentioned like, "Wow, you seem to stand all day." And I was like, "Oh, well, when I'm not in a meeting, that's when I'm sitting on the couch or a lounge chair or something." [laughs] I'm curious, though, because you are working in your dining living space if it's been harder to separate work and home life. JOËL: I think it was definitely an adjustment, but it's a thing that I learned to do. And I still try to keep some amount of separation, which is why I don't set up an office space in my room. But I've also gotten to the point where now that I work from home, I find myself leaving home much more frequently after the workday ends. I was surprised just how much social interaction you get just by default being in an office around people all the time. When you're at home all day, even if you're on calls, it's not the same. And so I've found myself more and more to stay in a healthy emotional, mental space, leaving the home in the evening to go do things with friends or with other people. And so even though I am an introvert who prior to working from home preferred to stay at home more evenings than not, I've started living almost more of what people would assume is an extrovert lifestyle where I'm out every evening. STEPHANIE: Wow, that's so interesting because I'm the opposite; where when I was commuting and going to an office, I found it much easier to stay out. I would just go to a bar or a restaurant after work. Whereas now it's a bit harder because I'm not already out and about in the world, and also I am in my comfy pants, and I'm just like, oh, I have to go out? I don't know if I'm up for that. [laughs] Though I also really...I think the downside is that I have been really missing some of that human contact. And there are weeks where I'm like, dang, I really didn't talk to people in the world very much. So it's actually been a bit of a bigger obstacle for me to find the energy to see people in the evenings after work. JOËL: It helps to make plans. STEPHANIE: Yeah, that's a good idea. JOËL: Or you can have people come to you. You mentioned you were doing that soup club. STEPHANIE: I did, yeah, back when the winter was first starting. I mentioned on the show that I was having people over for soup on Friday nights, and that was really great. That was nice because then I was like, okay, I have to sign off by 5:00 p.m. so I can start making the soup. [laughs] MID-ROLL AD: Debugging errors can be a developer's worst nightmare...but it doesn't have to be. Airbrake is an award-winning error monitoring, performance, and deployment tracking tool created by developers for developers that can actually help cut your debugging time in half. So why do developers love Airbrake? It has all of the information that web developers need to monitor their application - including error management, performance insights, and deploy tracking! Airbrake's debugging tool catches all of your project errors, intelligently groups them, and points you to the issue in the code so you can quickly fix the bug before customers are impacted. In addition to stellar error monitoring, Airbrake's lightweight APM helps developers to track the performance and availability of their application through metrics like HTTP requests, response times, error occurrences, and user satisfaction. Finally, Airbrake Deploy Tracking helps developers track trends, fix bad deploys, and improve code quality. Since 2008, Airbrake has been a staple in the Ruby community and has grown to cover all major programming languages. Airbrake seamlessly integrates with your favorite apps to include modern features like single sign-on and SDK-based installation. From testing to production, Airbrake notifiers have your back. Your time is valuable, so why waste it combing through logs, waiting for user reports, or retrofitting other tools to monitor your application? You literally have nothing to lose. Head on over to airbrake.io/try/bikeshed to create your FREE developer account today! JOËL: So you mentioned that sometimes it's hard to leave the home because you're kind of in your comfy clothes, and you don't want to kind of get dressed to go out. Has working from home kind of changed the way you tend to dress? Do you ever do the thing where it's like, oh, I've got the formal top and then just sweats? STEPHANIE: Yeah. Like business on top and party in the bottom [laughter] or something like that is the phrase. My habits around getting ready in the morning have definitely changed; where I don't put as much energy or effort, or time into it as I did when I was working in an office. And that has been nice because I get that time back, and that is really valuable to me. Yeah, I'm also usually just in soft pants. [laughs] That has definitely been a very positive impact on my life. And I do try to make an effort to go out for coffee. And when I do that, I'm just like, yeah, how I go out is how I go out. I don't really mind. I'm very comfortable going out however I'm feeling that day. But I think getting the time back actually has been really important to me. JOËL: Hmm, I think for me, interestingly, that's become an interesting way to build a little bit of separation from personal life and work life. So I'm making a point to put on...I don't know how you describe it. I was going to say real pants, but it's not like sweats are not real pants. But yeah, I will put on the kind of thing that I would put on to go in the office. And for me, that's kind of a...it's a start to the day. It's a start to being more serious and transitioning to more of a work mindset. STEPHANIE: Yeah, absolutely. JOËL: As opposed to on the weekend, if I'm just hanging around in the same space, but I'm dressed differently, I don't feel like I'm in work mode. STEPHANIE: Yeah, yeah, that's fair. I've definitely noticed your fun sweaters that you wear in video calls and stuff. So I really appreciate that; yeah, you are just putting on clothes that make you feel like you're ready to dive into the work week. I'm really curious, do you find yourself being more productive working from home than you were working in an office? JOËL: I would say it's about even on average. There are probably days where more or less on one side or the other, but I would say it's similar. STEPHANIE: I think I'm actually much more focused at home. And I know that this is not true for everyone because I was chatting with a friend, and she was asking, like, "How do you stay focused at home?" She was telling me that she gets so distracted by all the things that she could be doing in her home life. And for me, because I really enjoyed the social aspect of being in an office, I found myself wandering into the kitchen not infrequently to go get some snacks, and oh, running into this person and having a little chat. And I think my presence also, I was available for other people to come to me and start a conversation or ask to go on a walk. And I think I actually really needed that external push to take breaks. Because now that I'm working from home by myself, I definitely just get into some rabbit holes, and it's tough for me to resurface. JOËL: Let me fix one more error, and then maybe the test will be green. Oh, that didn't fix it, but I'll bet one more would fix it. And keep doing that until it's like, oh, well, I'm going to push off my break for another 30 minutes, oh, another hour. And it's like, you know what? I'm just going to finish my day. STEPHANIE: That literally happens to me all the time. The lunchtime break is tough because I definitely will delay that by 15 minutes and then 30 minutes, and then oh no, it's like 2:00 p.m. Okay, let me just eat a snack, then. And then keep going until I finish whatever task, and then end up wishing that I had made a little more of an effort to take a real break. JOËL: Yeah, I was having a conversation recently with someone about how it's often easier to make space for other people than for yourself. So if somebody is like, "Hey, I want to take a break. Do you want to go take a walk?" You might be like, "Sure." Maybe I wasn't quite in a place where I wanted to take a break, but I'll make the time for you. Whereas when it's like, you know what? My body or my mind is telling me I need to take a break, but this test isn't green yet. So I'm going to almost deny myself here for the, I don't know, the good of the mission, whatever. It's not really a noble sacrifice. It ends up hurting you and the project in the longer run, but it's so much easier to do that. STEPHANIE: Wow. Okay, yeah, that really resonated with me because I find myself in situations where I don't think that I can take a break because I'm like, oh, I have all these red tests, and I need to get them in a place where I feel comfortable stepping away. But if someone asked me like, "Hey, I'm at your door. Let's go for a walk," I could just put it away and go for a walk and have a great time. And I would like to be able to do that for myself when I don't have someone prompting me. JOËL: There's something I really appreciated that someone who used to be at thoughtbot would do is this person would go for a walk every afternoon without fail and would drop a line in the Slack channel being like, "Hey, I'm stepping away for a walk." And, I mean, yeah, it's nice to know that, okay, this person's not reachable for the next 15 minutes or whatever. But that's not really, I think, the value that I got from it. It was more of seeing somebody else taking a break and it being a reminder for me too to be like, you know what? Maybe I should take a walk as well, like, it might be time for a break. STEPHANIE: Yeah, I like that a lot. I think it's kind of ironic that I have quote, unquote, "optimized" my setup so much that I don't get distracted that I miss out on the friction laughs (A little call back to earlier.) that I would like to, yeah, call more mindfulness to how I'm physically feeling, not even physically but also emotionally and intellectually and being prompted, like I said, externally because I am realizing now that I really need that. JOËL: And at least for us here in North America, it's now starting to be spring. And so I think sometimes winter can be its own barrier to be like, you know what? I should go and take a walk. I don't know if I want to put on all the layers and my boots and all of that and deal with the snow. Whereas now it's like, just walk out and there will be flowers and trees covered in blooms. And it's going to be amazing. STEPHANIE: Yeah, I'm really looking forward to that. I agree; I think when the weather is nice, that is definitely a bigger motivator for me because there's more to enjoy and more to look at. And I love being outside. When you do step away to take a break, what do you do in your home or outside your home? JOËL: So I'm a big fan of taking a walk. I live in a dense, walkable neighborhood, Downtown Boston. And so just walking around a few blocks is a great way to get a little bit of fresh air, just get some motion going because I've been sitting around for a long time. It's a lot of natural beauty as well. A lot of people have gardens, and there are a lot of trees planted along the roads. So it's just a really pleasant way to, in some ways, connect with a little bit of nature and be outside and reset. Do you find yourself when you're looking for a break gravitating outwards or inwards in your space? STEPHANIE: I like to make myself a snack, a cup of tea. Sometimes if I'm reading a good book, I'll get into the book for 20 minutes. And sometimes, if there's nothing to pick up, maybe I'll find myself on YouTube and watch a short little thing just to reset and have some fun. Sometimes I'll try to tackle some dishes. I think the other thing with working from home is that I now create more mess in my home. [laughs] I don't know if it's the same with you. But I, yeah, try to keep on top of that so that I don't have to do it later in the evening. JOËL: I think one of the things that's really nice about working from home is the ability to cook more because you're in that space. So I've found myself oftentimes more on my lunch break, maybe prepping some things for a stew or something that's going to braise, and then just having it sit on the stove all afternoon. And like I said, maybe a really quick break is just you get up, go check the pot on the stove, and you turn the heat down or stir it a little bit and then get back to work. STEPHANIE: Yeah, I like that a lot. I do that, too, with a pot of rice or beans or something like that. I also am definitely making my own food for lunch a lot more just because, being at home, you have your whole kitchen and fridge available to you, and I feel less pressure to get all that done the night before. JOËL: Right. I think I've been trying to incorporate a little bit more physicality to my breaks recently. And one thing that I've done for shorter breaks...if it is a longer break, it is nice to go out and take a walk. But for shorter breaks, I set up a pull-up bar, and I just try to go and do a set of pull-ups there. And I'm not great at it, so it's not like I'm there for 10 minutes doing 100 pull-ups. But it's a nice way to go from a very static mental mode to a quick break that just totally resets you into this active physical space. STEPHANIE: Yeah, I like that a lot because something like that requires your full attention and physical effort in that moment. So it's not like you can still really be thinking about work while you're in the middle of doing a pull-up, at least [laughs] that's my interpretation of [laughs] how you take those breaks. JOËL: I'm curious, are there any other kinds of lifestyle elements that you've changed or customized to help you have a better working-from-home experience? STEPHANIE: There was a past Bike Shed episode hosted by Steph Viccari and Chris Toomey, and I can't remember exactly what it was that they were talking about. It must have been working from home-related because Chris had mentioned a ritual that he had when he was finishing his workday where he would close his laptop and say, "Schedule shutdown complete." And I've been thinking about that a lot and trying to do a similar thing of just verbalizing, "I'm done with work now," to make it true. [chuckles] Otherwise, if I don't, I can find myself gravitating towards my laptop when I have a thought. Like, I have an idea like, oh, I just thought of a way to try to debug that test or whatever. And then I'll want to go back just really quickly to write it down on my work computer so it's there for me when I come back. But if I've said, "I am done with work today," that means I'm trying not to reopen the work laptop, and then I'll try to jot it down somewhere else. And that has been really helpful. JOËL: So, setting like an emotional boundary. STEPHANIE: Yeah, an emotional boundary that almost becomes physical in a way because when I was working in an office, I would never take my work stuff home with me, so I physically could not access it. And since I can't do that now, by verbalizing it, it's almost as if I've created a boundary in my head. JOËL: That's really powerful, the impact that you can have just by sort of verbalizing something. STEPHANIE: I will say that I also don't keep any work stuff on my personal devices and that was true even when I worked in an office, but I think it has actually been more helpful and important working remotely. It sounds like you've experimented with a lot of different ways to make remote working work for you. And I'm curious if there's anything else that you really want to change or anything that you would like to try or do differently. JOËL: I think an element that I've been experimenting with recently is actually working outside of the home, so something like going to the library or going to a coffee shop. Interestingly, I've tended to use those mostly for when I want to work on personal projects that are not work. So strangely enough, now I work in my home, and when I do things for myself that I previously would have maybe done in my home, now it's always at a coffee shop, at the library, something like that. So I still keep that separation, but it's inverted. STEPHANIE: Wow, that's really interesting. I also like to be in a more public space as well with my work. And just being surrounded by other people and busyness is very comforting for me. And it actually also helps with the rabbit hole because I think I am more present in my environment when I do have cues of people getting up around me or whatever. Though ironically, my wanting to be around other people does not really work well with meetings and collaborating and pairing with other people. [chuckles] And so when I have to do those things, even though I'm also socializing just in a different way, I usually have to be in a more quiet, private space. JOËL: Have you ever tried to maybe group your meetings on a particular day so that you have, let's say, an afternoon of uninterrupted time that you know you can just go to a coffee shop and be heads down and not have to take a call there? STEPHANIE: I haven't tried that. But I think that would be helpful because then it's kind of like the best of both worlds, right? Where I can say, "Hey, I can meet once I'm moved back into my private space," and also have that physical environment of being around other people. And I think I had previously thought just those things were mutually exclusive, but there are certainly ways that I'd love to try injecting that into my home-work setup. I'm really glad that we ended up talking about this because I think this will just be our future for a while. And it's always worth revisiting it and thinking about it and thinking if it's working for us or not. I'm really excited to try some of the new things that you mentioned. Like, we've been doing this for several years now, but there's always room for improvement and room to inject more fun and joy, and creativity in how we choose to do our work. JOËL: On that note. Shall we wrap up? STEPHANIE: Let's wrap up. Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeee!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
Joël submitted a last-minute submission to RailsConf discreet math, which got picked up!
Today's episode is "Old News"! Stephanie shares her ergonomic desk setup. Joël talks about the pyramids. Another old thing is the Bike Shed episode two weeks ago about success and fulfillment. Stephanie and Joël realized off-mic that one area they didn't really talk about so much is impact, and that is something that is very fulfilling for both of them. Today, they talk about impact and leadership as individual contributors because leadership is typically associated with management. But they believe that as ICs, at any level, you can be displaying attributes of leadership and show up in that way on teams. This episode is brought to you by Airbrake (https://airbrake.io/?utm_campaign=Q3_2022%3A%20Bike%20Shed%20Podcast%20Ad&utm_source=Bike%20Shed&utm_medium=website). Visit Frictionless error monitoring and performance insight for your app stack. Success and Fulfillment episode (https://www.bikeshed.fm/376) Logitech MX Vertical (https://www.bestbuy.com/site/logitech-mx-vertical-advanced-wireless-optical-mouse-with-ergonomic-design-graphite/6282602.p?skuId=6282602&ref=212&loc=1&extStoreId=319&ref=212&loc=1&&&gclid=EAIaIQobChMItMP27PT8_QIVfMiUCR0_dwVqEAQYASABEgIWJ_D_BwE&gclsrc=aw.ds) Rose Wiegley's Lead From Where You Are (https://www.youtube.com/watch?v=1GorXHiB7nw) Transcript: JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. STEPHANIE: And I'm Stephanie Minn. And together, we're here to share a bit of what we've learned along the way. JOËL: So, Stephanie, what's old in your world? STEPHANIE: I'm glad you asked that question because I don't think we get a chance to talk about things that are exactly the same as they've always been. And so today, I'd like to share my ergonomic desk setup, [laughs] which has been old for about a year or so. And back then, I was having some issues with some back pain and some wrist pain, and I made a few upgrades and since then have not had any issues. And I feel like it's one of those things that I just forgot about because when it stops being a problem, you don't really notice it. And today, I am able to reflect on my old problem of bodily pain while working. And I'm happy to say that things have been much better for a while now. JOËL: Oh, that's amazing. What's one thing you think had the most impact in your setup? STEPHANIE: Oh, I picked up one of those vertical mice for my wrist. I was having some wrist pain, like I mentioned. And I actually solicited some input from other thoughtboters for the best mouse to replace the Apple Magic Mouse that I was using, which I really wanted it to work for me because I liked the way it looked, but nevertheless, that was causing me issues. So I ended up with the Logitech MX vertical, and that has really solved my wrist pain. It is very not cute. [laughs] It kind of looks like a weird big, gray snail. But you know what? You got to do what you got to do. JOËL: That sounds like an art project waiting to happen. STEPHANIE: Yeah. I would love to see; I don't know, a way to make these vertical mice look a little more cute. Maybe I will stick some googly eyes or something on it and then just be like, this is my pet snail [laughs] that works with me every day. JOËL: Do you have a name? STEPHANIE: Not yet. Maybe I'll save it for what's new next week. [laughter] JOËL: Homework assignment. Years ago, I was also having some wrist pain. And I think one of the most impactful things I did was remapping some keys on my keyboard. So I'm a pretty heavy Vim user. And I think just reaching with that pinky for the Escape key all the time was putting a lot of strain on my wrist. So I remapped Caps Lock to control. That's what I did. Yes, because it was reaching down with the pinky for the Control key and remapped escape to hitting J twice. So now I can do those two very common things, Control for some kind of common chord and then Escape because you're always dropping in and out of modes, all from the Home row. And now, both my hands feel great, and I can be happy writing Vim. STEPHANIE: That's really nice. I think when I had asked in Slack about mouse recommendations, someone had trolled me a little bit and said that if I just use my keyboard for everything, then I won't need to use [laughs] a mouse at all. [laughs] So there's also that option too for listeners out there. JOËL: It's true. You go to tmux and Vim, and on a Mac, maybe something like Alfred and a few OS shortcuts, and you can get 90% of the way to keyboard only. STEPHANIE: What about you, Joël? What's old in your world? JOËL: So you know what, something that's really old? Pyramids. STEPHANIE: Wow. [laughter] I should have known that this is where we were headed. JOËL: Long-term listeners of the show will know I'm a huge history nerd. And we think of the pyramids as being old, but they are ridiculously old. A fun fact that I have not learned recently because this is something that is old in my world, but that I learned a while back is that if we look back to Cleopatra, the last Pharaoh, she is closer to us in time than she was to the building of the Great Pyramid. STEPHANIE: No. What? Wow. Okay, yeah, that definitely just messed with my brain a little bit. And now, I have to rethink my understanding of time. JOËL: I think the way the timeline sort of works in my mind is it tends to get compressed the further back you go. So it's like, yeah, I think of modern-ish times, like, yeah, there's like a lot of stuff, and I'm thinking in terms of decades until maybe like the 1900s. And now I start to think in terms of centuries. And they're kind of more or less equivalent, you know, the Victorian Age. It fills about the same amount of space in my mind as like the '60s. And then you get to the point where it's just like millennia. STEPHANIE: Mm-hmm. When you think of Ancient Egypt, do you think Cleopatra and also pyramids, so you kind of conflate? At least I do. I conflate the two a little bit. But yeah, I guess a lot of time passed in between that. [laughs] JOËL: The pyramids are also really cool because they were one of The Seven Wonders of the ancient world, which is sort of, I want to say, like a tourist circuit created by the ancient Greeks, sort of like monuments that they thought were particularly impressive. But they're also the only ones that are still standing; all of the others have been lost to time. STEPHANIE: Wow, it's the real wonder then [laughs] for being able to stand the test of time. JOËL: It's also the oldest of the seven and has managed to survive until today, so very impressive. STEPHANIE: I love that. Just now, when you were talking about thinking about time periods kind of compressed, I definitely fall victim to thinking that the '70s or whatever was just 30 years ago, even though we are solidly in the 2020s and, in reality, it's obviously like 50. But yeah, I think that always freaks me out a little bit. JOËL: Yes, it's no longer the year 2000. STEPHANIE: Turns out. [laughs] So, in case our listeners didn't know. [laughs] JOËL: I think when we were close-ish to the turn of the millennium, it just made mental math so easy because you're at that nice zero point. And then you get to the early 2010s, and it's close enough within a rounding error. And now we just can't pretend about that anymore. STEPHANIE: No, we really can't. JOËL: We need a new anchor point to do that mental math. STEPHANIE: I love that we're talking about what's old in our world because I love a chance to just repeat something that I've said before that I still think is really cool, but I feel like that doesn't get invited as frequently. It's just like, oh, how are you doing? What's new? So yeah, highly recommend asking people what's old in their world? JOËL: Yeah. And beyond that, not just like, what are some new things you're trying? But kind of like what you were talking about earlier, what's something that's stayed stable in your life, something that you've been doing for a while that works for you? STEPHANIE: Yeah, I love it. So another thing that's old is our episode from a couple of weeks ago about success and fulfillment. And you and I realized off-mic that one area we didn't really talk about so much is impact, and that being something that is very fulfilling for both of us. And that kind of got me thinking about impact and leadership. And I especially am interested in this topic as individual contributors because I think that leadership is typically associated with management. But I really believe that as ICs, at any level, really, you can be displaying attributes of leadership and showing up in that way on teams. JOËL: Definitely. I think you can have an impact at every level of the career ladder, not just an impact on a project but an impact on other people. I remember the first internship I did. I was maybe two weeks in, and I had a brand new intern join. It's day two, and I'm already pairing with him and being like, "Hey, I barely know anything about Rails. But if you want help with understanding instance variables, that's the one thing I know, and I can help you." STEPHANIE: Yeah, that's awesome. I mean, everyone knows something that another person doesn't. And just having that mindset of injecting leadership into things that you do at work, no matter how big or how small, I think is really important. JOËL: I think there's maybe a lie that we tell ourselves, which is that we need to wait to be an expert before we can help other people. STEPHANIE: Yeah, I've certainly fallen into that trap a little bit where I think it's held me back from sharing something because I assumed that the other person would know already or the thing I'm thinking is something I learned but not necessarily something that someone else would find interesting or new. JOËL: Right. Or even somebody's looking for help, and you feel like maybe you're not qualified to help on that problem, even though you probably are. STEPHANIE: One thing that I was really curious about is, can you remember a time when an IC on your team demonstrated leadership, and you were really impressed by it? Like, you thought, like, wow, that was really great leadership on their part, and I'm really glad that they did that. JOËL: Yeah. So I think one way that I really appreciate seeing leadership demonstrated is in client communication. Typically, the teams we have at thoughtbot are structured on a particular project where there's like a team lead who is in charge of the project. It's usually a couple of consultants working together as peers. Depending on the situation, one or the other might take leadership where it's necessary. But I've really appreciated situations where a colleague will just really knock it out of the park with some communication with the client or when they are maybe helping talk through a difficult situation. Or maybe even we realize that there's a risk coming down the pipeline for the project and raising it early and making sure that we de-risk that properly. Those are all things that I really appreciate seeing. STEPHANIE: Yeah. I think the way folks engage in channels of communication can have a really big impact. A few things that come to mind for me that I think is really great leadership is when more experienced or senior folks ask questions in public spaces because that kind of cultivates a space where asking questions is okay, and even people who have whatever title or whatever years of experience they still have questions and can signal to other folks in the team that this is okay to do. And the same thing goes for sharing mistakes as well. Also, just signaling that, like, yeah, we mess up, and that's totally normal and okay. And the consequences aren't so scary that people feel a lot of pressure not to make mistakes or share when they happen. JOËL: Yeah. The concept you're describing is very similar to the idea of vulnerability. STEPHANIE: Yeah, that sounds right. JOËL: So kind of modeling that from more senior people helps create a safer environment for the more junior people. STEPHANIE: I think another thing that I really love that others do for me, and something that I want to get better at doing for others, is speaking up when something is a little off because, again, with power dynamics, for people who are newer or less experienced, they might be noticing things, but they don't feel encouraged to speak up about it in a public space or even with their manager. But they might confide in another IC who is maybe a little more senior. And one thing that I really liked that happened on my client project recently is a senior engineer said in Slack, "Hey, I noticed some sentiment from our daily sync meeting that we're cutting it close to our deadline." And he asked like, "Should we shift some priorities around? Or what is more important to make sure that we focus on in the next few weeks before the end of the quarter?" And I was just really glad he said that because I certainly had been feeling it. But I don't know if I necessarily kept a pulse that other people were also feeling it. And so having someone keeping an eye on those things and being receptive to hearing that from folks and then being like, okay, I want to make sure that I bring it up to the manager because it's important. I thought that was really cool. JOËL: Yeah. Now we're almost dialing into sort of emotional awareness of what other people on the team might be feeling and also the ability to think in terms of risks and being proactive about managing those. STEPHANIE: I like your use of the word risks because that definitely feels like something that, in general, people are scared to bring up. But ultimately, it is the signal of someone who is experienced enough to know that it's important to make transparent and then adjust accordingly. Even beyond noticing what folks are feeling, there are also more concrete things that can be noticed as well, like if team members are complaining about CI build time being really long and that being a repeating issue in getting their work done. Or any other development or tooling thing that is causing people issues, having someone notice how frequently that happens and then being like, hey, this is a problem. And here's what I think we should do about it. JOËL: So not only the awareness but also the initiative to try to enact change. STEPHANIE: Yeah, absolutely. MID-ROLL AD: Debugging errors can be a developer's worst nightmare...but it doesn't have to be. Airbrake is an award-winning error monitoring, performance, and deployment tracking tool created by developers for developers that can actually help cut your debugging time in half. So why do developers love Airbrake? It has all of the information that web developers need to monitor their application - including error management, performance insights, and deploy tracking! Airbrake's debugging tool catches all of your project errors, intelligently groups them, and points you to the issue in the code so you can quickly fix the bug before customers are impacted. In addition to stellar error monitoring, Airbrake's lightweight APM helps developers to track the performance and availability of their application through metrics like HTTP requests, response times, error occurrences, and user satisfaction. Finally, Airbrake Deploy Tracking helps developers track trends, fix bad deploys, and improve code quality. Since 2008, Airbrake has been a staple in the Ruby community and has grown to cover all major programming languages. Airbrake seamlessly integrates with your favorite apps to include modern features like single sign-on and SDK-based installation. From testing to production, Airbrake notifiers have your back. Your time is valuable, so why waste it combing through logs, waiting for user reports, or retrofitting other tools to monitor your application? You literally have nothing to lose. Head on over to airbrake.io/try/bikeshed to create your FREE developer account today! STEPHANIE: So you and I are actually working on the same client but on different project teams. And you've been involved with making improvements to CI to reduce kind of the problem that I was just talking about where it takes a while for us to develop. And you are working on reducing the number of days between the master branch and when you are allowed to hit the merge button to make sure that feature branches had incorporated the latest changes for master. And one thing that I really like that you did was you solicited folks' input for what that time range should be. So I think you were playing around with the idea of giving people three days to merge, or else they'd have to rebase. JOËL: I thought it was being really comprehensive here with three days because, you know what? You solicited feedback, you got review, but maybe it's the end of the day, or maybe someone's in different time zones. So we definitely want to cover at least a 24-hour period. So three days gives you an extra day. It should be safe. Is there any common situation where you might want a PR to be open for more than three days, but you wouldn't have rebased the latest master changes? STEPHANIE: Yeah. I can see how you thought about it from a few different angles too. Like, you're thinking about time zones and folks working in other regions. And I ended up responding to you, and I was like, oh, what about the weekend? [laughs] JOËL: Oops. STEPHANIE: Because three days seems a little short if two of those days are eaten up by Saturday and Sunday. But what I liked was that you said, "Hey, I'm thinking about doing this. What do other people think?" Because you didn't claim to know what works best for everyone. And I think that's a really important skill to be honest, soliciting others for feedback, and knowing who to ask for and who to make sure you are not negatively affecting their work by making a change or making a decision. JOËL: And in this case, it helped me realize that I had skipped over the most obvious edge case while thinking I'd covered all the really niche ones STEPHANIE: We got there in the end, [laughs] and I think made the most informed decision. JOËL: I guess that's just good product design in general. Talk to your users, get early feedback, put a prototype out where necessary. You don't always want your users to dictate what you will do, but it's good to get their feedback. And similarly, I think that applies when working with dev-facing things; you want feedback from developers. If I asked everybody at the company, I would have gotten a lot of different answers. And I might not have gotten one that satisfied everybody. But having some of that feedback helps me make a more informed decision. STEPHANIE: Yeah, and to take it to the next step, I think there's also accountability for those decisions that you have to have. So if the decision that you made ends up being like a huge pain for some unforeseen reasons, I imagine you'd be on top of that as well and would want to figure out how to adjust if the experiment doesn't work as well as you would have liked. JOËL: Right. I think we often talk about failing early. In fact, we have a recent episode about dealing with failure. And we mostly talked about it from a technical perspective, catching errors or making code more resilient to failure. But there is also a human component of it, which is if you catch errors or design problems, and I'm using design here as a product design, not in visual design, at a prototype phase or maybe a user interview phase, you've saved yourself a lot of maybe unnecessary work that you would have had if you went out to the product phase and shipped it to your entire customer base. I guess, in a sense, it's worth thinking about other developers, the engineering team as customers sometimes. And a lot of the internal facing parts of your project are effectively a product geared towards them. They are the users. And so, throwing in a little bit of product development and design skills into building internally-facing software can have a huge impact. So beyond just thinking of developers as a sort of internal customer base, occasionally, we work on projects where you are building internal tooling for other teams; maybe it's business development, maybe it's the marketing team, maybe it's some form of customer support. And that can often have a really large level of impact. Have you ever been on a project like that? STEPHANIE: I have. One of my first jobs was for an e-commerce company. And I built tools for the customer support team for dealing with customers and getting their orders correct and fixed and whatnot. So I did work on an admin dashboard to make their jobs easier as well as the company also had its own internal software for dealing with warehouse logistics. And so, I also built a little bit of tooling for our logistics and fulfillment team. And I really liked that work a lot because I could just go over and talk to the folks internally and be like, "Hey, what did you mean by this?" Or like, "What do you want here, and what would make your life easier?" And I felt a much more tangible impact than I did sometimes working on customer-facing features because I would deliver, and that goes out in the world. And I don't get to see how it's being used, and the feedback loop is much longer. So I really liked working on the internal tooling. JOËL: In my experience, those teams are often really underserved when it comes to software. And so it's possible to make a huge impact on their quality of life with relatively little work. Sometimes you can just take an afternoon and eliminate a thing that's causing them to pull out their hair. STEPHANIE: Yeah, absolutely. And you get the satisfaction of knowing that you built something exactly as they wanted it. Whereas sometimes, with user or customer-facing features, we are guessing or experimenting a little bit. And yeah, I think having someone who then is very grateful for, I don't know, the button that you added that makes them have to click less buttons [laughs] when they do their work in an internal dashboard can feel really good. JOËL: Having that direct access can be really nice where you get to just go over and talk to them or shadow them for a day, see how their work happens, get to hear their frustrations real-time. It's often a smaller group as well than you would have for our customers, which might be thousands of people, and so you sample a few for user testing. But for an internal team, you can get them all in a Zoom call. I don't necessarily recommend doing a giant Zoom call for this kind of thing, but it's a small enough group that you could. STEPHANIE: I'd like to flip that around to you. Have you ever been on the receiving end of an improvement or someone else making your life a little easier, and if you could share what that was and how it made you feel? JOËL: I think pretty early on in my career, one of my first projects for thoughtbot, we were building a small kind of greenfield app for a startup. And another member on the team took a couple of hours one afternoon to just write a few small abstractions for the test suite that; just made it so much nicer to write tests. And we're pretty scrappy. We've got a tight deadline, and we're trying to iterate very quickly. But that quality of life difference was significant to the point I still remember this ten years later. I think we were rotating this developer off, and this was kind of a farewell present, so... STEPHANIE: That's really sweet. JOËL: You know what? I love that idea of saying when you rotate off a project, do a little something extra for the people you're leaving behind. STEPHANIE: Yeah, I love that too. It's your kind of like last chance to make a small impact in that world. JOËL: Especially because on your last couple days, you're probably not expected to pick up a ticket and get it halfway done. So as you're kind of ramping down, you might have a little bit of time to do some sort of refactoring task or something that needs to get done but hasn't been prioritized that will have a positive impact on the team. STEPHANIE: Yeah, or even writing a script to automate something that you have kind of developed the muscle memory for, like, oh, I run these three commands in succession. And if you could just wrap it up in a little script and hand it off to someone else, it is a very sweet parting gift as well. JOËL: Absolutely. So I'm curious, we opened the topic talking about impact, and you immediately connected that to leadership, and I want to explore that idea a little bit. Do you think impact has to be connected to leadership? Or are there ways to have impact, maybe outside of a leadership role? STEPHANIE: I think they kind of go hand in hand, don't you? Because if you are wanting to make an impact, then in some ways, you are demonstrating that you care about other people. And at least for me, that is kind of my definition of leadership is enabling other folks to do better work. And you and I talk about attending and speaking at conferences pretty frequently on the podcast. And that is a very clear way that you are making an impact on the community. But I also think that it is also a demonstration of leadership that you care enough about something that you want to share it with others and leave them with something that you've learned or something that you would like to see be done differently. JOËL: And just to be clear here, the way you're talking about leadership is not a title; it's an action that you do. You're demonstrating leadership, even if you don't have any form of leadership title. STEPHANIE: Yeah, absolutely. I think that because software development is a collaborative job, in some ways, in most things we do, there is some form of leadership component, even if you're not managing people or you don't have a particular title. JOËL: Like you said, it's about the things that you're doing to enable other people or to act as a sort of force multiplier on your team rather than how many people report to you in the org chart. STEPHANIE: Yeah, absolutely. JOËL: So if everybody aspires to enable each other and to be impactful, is it possible to have a team where every person on the team is a leader? STEPHANIE: Whoa, [laughs] asking the big questions, Joël. I mean, logically, the answer seems to be no based on our traditional understandings of leadership and being a leader or follower. But I also kind of disagree because, as developers, we have to make choices all of the time, and that can be at the level of the code that we write, the commit messages we write, what we communicate in our daily sync. And those are all opportunities, I think, to inject those skills that we're talking about. And so, yeah, everyone on the team is making decisions about their work. And inherently, to me, at least, the way you make those decisions and the impact of those decisions imply some form of leadership. What about you? What do you think about this? JOËL: It's tough because you can get into bikeshedding the definition. STEPHANIE: [laughs] JOËL: Which, hey, it's all about that, right? You know, is leadership about authority or decision-making capacity? Is it about impact? Is it about maybe even responsibility if things go wrong? Who's responsible for the consequences? It could be about position in the org tree and relative depth on that tree, to use some data structure terminology. But I liked your emphasis on the idea of impact and enabling others. So now it's a thing that you do. And so any member at any moment can be demonstrating leadership or acting in some leadership capacity, and they're contributing to the team in that way. And in the next moment, somebody else stands up and does the same thing. And it doesn't necessarily have to be in conflict. You can actually be in a beautiful harmony. STEPHANIE: Yeah, I really like the way you said that. I love a good beautiful harmony. [laughs] I think part of what has shaped my view on this is a keynote talk from RubyConf Mini back in November by Rose Wiegley. And her talk was called "Lead From Where You Are." And I think perhaps I've kind of internalized that a little bit to be like, oh yeah, everything we do, we can make a decision that can have a positive impact on others. So that has helped me at least feel like I have a lot more agency in what I do as a developer, even if I don't have the concrete responsibility of being a mentor to a particular person or having a direct report. It injects meaning into my work, and that goes back to the fulfillment piece that we were talking in, knowing that, like, okay, like, here's how I can make an impact. And that's all just wrapped up together. JOËL: So you kind of defined earlier the idea of leadership as work that has impact on others or that enables the work of others. And I think that there are some forms of that work which are kind of highly respected and will get you noticed and will be kind of called out as like, oh, you're performing leadership here. You stood up in that meeting, and you said the hard thing that needed to be said. And there are other forms of supporting or enabling the team that almost get viewed as the opposite of leadership that don't get recognized and are almost like you're seen as less of a leader if you're spending a lot of your time doing that. That can be sometimes more administrative work. How does that sort of fit into this model where we're talking about leadership as something that has an impact on others? STEPHANIE: Yeah, I'm glad you mentioned that because I have a lot of gripes [laughs] and thoughts, I suppose, about what work is visible and not visible and valued more or less. And I do think some more traditional signals of leadership, like talking the most in a meeting, like, that I don't necessarily think is my definition of leadership; in fact, the opposite. A true leader, in my opinion, is someone who makes space for others and makes sure that all voices are heard. And yeah, I guess it just speaks to like what I was saying about soliciting other people for feedback as well. It's like someone to me who demonstrates leadership is not someone who thinks that they have all the right answers but actively seeks out more information to invalidate what they think is right and find the right solution for the folks on their team. Similarly, in Rose's talk, she also mentions the idea of being a problem finder, so not just being tasked with solving a problem but looking around and being like, okay, like, what aren't we talking about and that we should be? And obviously, also contributing to making that better and not just being like, "Here's a bunch of problems, [laughs] and you have to deal with it," but that proactive work. Ideally, we are addressing those things before they become a huge problem. And I really liked that aspect of what leadership looks like as well. JOËL: Yeah, I think something that I've noticed that I do more as I've built more experience over time is that when I started off earlier in my career, it was a lot of here's a problem that needs to be solved, go and solve it. And then over time, it's what are the problems that need to be solved? You have to sort of figure out those problems before you go and solve them. And then sometimes it's even one level above that; what questions should we be asking so that we can find the problem so that we can solve them? And that will happen...it could be internally, so some of the things that I'm doing currently around improving the experience of a test suite is like, okay, we know sort of that it's slow in certain ways. How can we make that faster? We know that the experience is not great. But what are the actual problems that are happening here, the root causes? Or we're getting some complaints, but we don't really know what the underlying problem is. Let's go and search that out. STEPHANIE: Yeah, that brings to mind an issue that I think I see a lot on client projects where perhaps stakeholders or an engineering manager is seeing that we are slow to merge our PRs, and they kind of start reaching for solutions like, okay, well, people should spend more time doing code reviews or whatever, thinking that that's what the issue is. But in reality, maybe it's, I don't know, it can even be something as lower level as having to re-request reviews every single time you push a new commit because the GitHub settings are such that it requires additional approvals for every new change. And that is something that they would not know about unless someone spoke up and said, "Actually, this is what's causing us friction," and having to go back and do these manual tasks that maybe we should explore a different alternative to solve. JOËL: Yeah, instead of just jumping in with a solution of we need to throw more dev hours at this problem, it can be useful to step back and ask, okay, well, why do we have this problem in the first place? Is it a process issue that we have? Is there some sort of social element that we need to address and organizational problems? And if it's not that, then what are the questions that we're missing? What questions should we be asking here to understand this problem? STEPHANIE: Right. And even speaking up about it too and going against someone's assumption and saying, "Here's what I've been seeing, and this is what I think about it," that takes a lot of courage. And I do think it is something that is especially important for folks who are more experienced and have more responsibility or a higher-level title, but ideally is something that anyone could do. I would love to know for you, Joël, what is the most important way that you want to make an impact as a developer? JOËL: I think the human element is the most important. I want to have an impact on my colleagues, on the dev teams with my clients. I want to ship good work. But I think the most valuable thing to invest in is other people. STEPHANIE: Yeah, I agree. I think for me; it's like making a good work experience for the people that I work with. And it's also a little bit selfish because then that means I am having a good work experience, and I'm in a good culture and environment. But that is definitely an area that I spend a lot of time thinking about and wanting to start conversations about. JOËL: It's a win-win, right? You make it better for everybody else and better for you in the process. STEPHANIE: Exactly. JOËL: And it's okay for it to be somewhat selfishly motivated. Like, it doesn't have to always be every day super altruistic like; I just want to make the world a better place. STEPHANIE: [laughs] JOËL: Like, you know what? I want my corner of the world to be better, and in doing so, I'm going to make it better for everyone else. STEPHANIE: What's that phrase? The tide rising all the ships. [laughs] That is extremely not correct, but I think you know what I'm trying to say. JOËL: I think a rising tide lifts all boats. STEPHANIE: Yeah, something like that. I love a good rising tide. [laughs] On that note, shall we wrap up? JOËL: Let's wrap up. Or let's rise up. STEPHANIE: [laughs] STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeee!!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
Joël is a mentor for RailsConf and got matched with a speaker. Stephanie has been having trouble stepping away from her work. It's frustrating when chasing down a bug because something's gone wrong, and you spend a whole afternoon figuring out where it is. Joël and Stephanie discuss error handling as a possible solution. This episode is brought to you by Airbrake (https://airbrake.io/?utm_campaign=Q3_2022%3A%20Bike%20Shed%20Podcast%20Ad&utm_source=Bike%20Shed&utm_medium=website). Visit Frictionless error monitoring and performance insight for your app stack. Mis en Place Writing (https://www.swyx.io/writing-mise-en-place) Errors accumulate at boundaries (https://thoughtbot.com/blog/testing-your-edge-cases) Retryable errors (https://thoughtbot.com/blog/handling-errors-when-working-with-external-apis) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn. JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way. STEPHANIE: So, Joël, what's new in your world? JOËL: So recently, RailsConf has closed out their CFP, and they've started sending out acceptances and rejections for proposals. And one thing that they do that I think is really nice is that they offer first-time speakers the ability to get matched with a speaker-mentor, somebody else who has given talks before that can help them prep their talk, listen to them rehearse, that kind of thing. And so they had put out a call for mentors last week. I responded to that, and I got matched with a speaker today. STEPHANIE: Cool. Is this your first time being a speaker-mentor? JOËL: First time for RailsConf. I've done it for another conference before. STEPHANIE: That's really exciting. What do you like about playing that role? JOËL: So I very much like prepping and giving talks myself. And I really value if there's something that I'm excited about sharing it, helping others build up that skill as well. So I think it's a great opportunity. I also remember what it was like when I was a first-time speaker and just how very nervous I was and not sure. So I think having someone who can play that role is an opportunity to have a really powerful impact in what's oftentimes, I want to say, a monumental moment. But it's kind of like a milestone marker moment in someone's career, the first time I gave a talk at a conference. So you get to help them to make that moment the best it can be. STEPHANIE: I love that, yeah. You make a really great point that after you've been speaking for a while, you maybe might forget what it felt like to give your first talk and how big of a deal it is. And in general, I think one thing I really love about Ruby Central conferences is how supportive they are of first-time speakers. So even in the CFP, they mentioned that they welcome first-time speakers and want to make sure to accept talks from those folks and then provide them support through this mentor program. And yeah, it just makes me feel really happy. JOËL: Do you remember your first talk? STEPHANIE: I do. So my very first talk I gave virtually at RubyConf in 2021. And then last year was actually my first in-person talk. And I remember even though it was technically my second talk; it was really my first talk in front of an audience. And I saw speakers in the Slack workspace asking questions about the AV setup, and I didn't even think to consider that in my preparation. So it was nice. Even though I didn't get set up with a mentor, to share a space with other experienced speakers and see what kinds of things they were asking about or what kinds of things they were sharing in that Slack space was helpful for me. JOËL: So when you do a proposal, do you typically have an outline already built out, or is it mostly a concept that you're pitching, and then you maybe start with an outline? Or where do you go next after a proposal has been accepted? STEPHANIE: That's a great question. I think first, I procrastinate for several months, [laughs], but I do try to write an outline in the proposal when I submit it so I do have a starting point. And I think that actually helps the CFP committee, too, when they are evaluating proposals to kind of get a better idea of what the talk will be about. And so, in my ideal world, I already have some structure, so by the time I've procrastinated to the point where it's a month or so before the conference itself, [laughs] I have an outline. And I end up writing words, like, I will just write my talk as if it were an essay with this bullet point outline already. And I find that helpful for me because I definitely have a bit of a stream-of-consciousness productivity energy. And so if I just put it all out there, I will then go back and be very ruthless, I suppose, in my editing, and I think that's where the magic happens. So I kind of let myself just word vomit all over the page. And then the real work comes in the editing process and organizing and making sure it sounds the way I would want it to sound when I'm speaking. And yeah, that's how it has worked for me so far. JOËL: So you have a sort of a separate phase for sort of just stream of consciousness dumping and then separately editing. And having those two separate is an important part of your process. STEPHANIE: Yeah, I think so. I don't do as well trying to imagine the structure and everything perfectly the first time around and then filling things in. I find that just putting everything out there and, you know, a lot of things get cut. But that works well for me. What about you? What is your typical conference talk writing process? JOËL: I think mine is a little bit more iterative. I tend to put in some pieces that I like and then try to connect them together, try to make sure it's telling a story. I think a lot about the pedagogical side of things, where people are going to be confused, where they're going to have questions, where they might check out. And then very early, start doing kind of draft rehearsals where I'm starting to work on the talk. And I will stop halfway through because, in my mind, I'm trying to seat myself in the audience and be a person who's listening. And there might be a moment where I'm like, wait a minute, you just jump from one thing to another, and I don't get the logical connection here. And I might pause right there in the rehearsal and add in, say, okay, we need a transitional point, or we need to explain a concept between these two. And I keep doing that until I can get through the whole thing and then realize it's way too long and start cutting. And I cut aggressively, and now it's too short. And now I go through it again. And again, people have questions in the audience, hypothetical audience; I am the audience. And so I really kind of inflate it and then cut it down and re-inflate it and cut it down a bunch of times until I'm happy. STEPHANIE: I like that a lot. That sounds right. That sounds very you to work even on a conference talk iteratively. JOËL: It's very time-consuming. So I don't know it's the most efficient way to build a talk, but it's a process that works for me. STEPHANIE: Yeah, that's true. And then there's value in the journey, even if the talk ends up changing from the very beginning to the end product. JOËL: So the approach that you described for yourself, I think, where you have a rough draft, and you're separating the editing from almost like a creative process, reminds me a lot of an article that I read called "Mise en Place Writing" by...I'm not sure what their full name is. They go by the handle Swyx. This is an article about their process for writing, but I think it applies to conference talks as well. Have you seen this article? STEPHANIE: I haven't. But that, I think, is similar to how I've thought about it or I've seen or heard other authors talk about their writing process and it being kind of similar where the creative work...they give themselves a lot of grace and just letting it be. And then the, like I mentioned, real work is in the editing process. It's kind of two different mindsets, I think. JOËL: We'll link the article in the show notes. STEPHANIE: I'm curious then how you incorporate visuals into your process because I think that's where my workflow is a little less successful because I'm not really thinking about visuals along with the words, and they do feel more like an afterthought. And I've always been really impressed when people who give talks can have a really visual and dynamic slide presentation. How does that work for you? JOËL: So I think I try to avoid slides that are three bullet points in the slide, and then I'm going to talk about it for three or four minutes for each bullet point. People read those quickly and then check out. I'll oftentimes try to have, like, turn each of those bullet points into a full-on slide. And maybe it's just a title and a fun picture or something like that. What this ends up doing is I kind of really inflate my slide deck. I'm going through maybe 80 or 100 slides in a 30-minute presentation. So it's multiple slides a minute. They move by really quickly. So I usually have either just an image or a header. I will usually start by just sketching it out with headers and then, where it makes sense, using an image. An image can be just for fun, or it can be something like a diagram where it is trying to illustrate a point. STEPHANIE: Yeah, I like that. I think talks with a lot of slides that are mostly just images or something that you can grasp in a few seconds are really engaging because you're keeping it moving, and you don't really let people get bored. And so you show a new slide, and they look at it, but then they are able to direct their attention back to what you're saying. JOËL: It's fun too with images because you can reuse them, and then they become a way to connect people back to a theme or let them know that you're making the same point again. A lot of talks, I will have a central theme that gets repeated. I'll often have a slide with some fun image with my key point on it. And then that slide will show up three or four times in my presentation oftentimes because each of the main points I'm trying to make kind of culminates at that same takeaway. And so for example, in the talk I gave at RubyConf Mini last fall, I had a slide about writing Ruby code being delightful. I think having some children being happy with just a big title being like, "Oh, delightful," or something like that. And after each of my examples where we went from code that was less good to something that was more idiomatic, Ruby that was really fun to work with, I would finish on that slide and be like, hey, our code is now delightful. And hopefully, that helped people with the takeaway of, like, we want to write delightful code. Ruby has tools to do that. And then, hopefully, they either remember the things they can do to get to that point or can look it up and find a talk online. STEPHANIE: Yeah, I watched that talk, and I really vividly remember that slide and the theme that you were trying to hone in on. So I thought it was pretty effective. I think this makes me realize speaking, I mean; speaking is obviously a skill but even the process of creating a talk in that particular medium is also a vast skill and can go...there are so many different styles and flavors. But I really think that what you said will get me thinking next time I'm writing my talk and how I can better incorporate that kind of engagement with the audience and making sure that the way I deliver the talk is just as thoughtful as the content itself. JOËL: Yeah, I've been putting a lot of thought into what makes a good talk and what elements are unique to my process, what elements can be useful to others because now I have to coach someone else on their process and say, "Hey, here's the thing that worked for me. Maybe this will be helpful for you." Or maybe it's just, "Have you tried this?" Or "I think audiences will be asking this question at this moment, what do you think of this?" So that's definitely been top of mind in a whole other dimension for me recently. How about you? What's new in your world? STEPHANIE: So before we started recording, I was heads down deep in the muck of trying to write some tests, some RSpec tests on my client project. And the domain for this client project is really big. There are a lot of models. And I was starting to go deep into the factory setups for our test fixtures. And it was hairy. And I was just going further and further down the rabbit hole to the point where I was skipping lunch. JOËL: Ooooh. STEPHANIE: Yeah, I was like, I couldn't pull myself away from it, and I kind of regret it a little bit. [laughs] And so I was just thinking about, like, how can I incorporate taking breaks a little bit more and feeling better about stepping away from the work when I'm really deep in it? You and I had this standing appointment to record [laughs] a podcast, so that was kind of the signal to me that it was time to try to set it aside. And I did end up taking the dog for a walk around the block beforehand to get some fresh air, but yeah, it was a little rough, I don't know. How do you deal with just being so deep in the code that you don't really want to resurface? JOËL: That's hard because sometimes I'm feeling productive, and I don't want to stop because I feel like I might not get back into the flow quite as easily. Sometimes it's just out of frustration. It's like, oh, I'm just so close to getting this bug done. If I get this one more test to pass, then I'll be good. And I keep doing one more thing. And the next thing I know, I have skipped lunch, and it's late in the afternoon. And it's just like; it's been a frustrating day. STEPHANIE: And you're cranky, yeah, yep. I know that feeling. JOËL: I've stopped being productive for the past hour. But I'll be like, one more thing, one more thing. STEPHANIE: I think I was in that place because I was starting to get deep into the internals of models completely unrelated to the test that I was writing, but that was just where the rabbit hole led me. And I think after this, I will go and ask in Slack for a pair because I think that would be really helpful right now. I've just reached the limits of what I know. And I'm almost positive that someone knows how to do this more efficiently than I do. So that was a bit of a signal to me, but it was very challenging untangling myself out of that headspace. JOËL: Have you ever played the video game Civilization? STEPHANIE: No, I haven't. JOËL: It's a turn-based historical strategy game. The running joke about it is that people get really pulled into it. And they're always just saying, "I'm going to play one more turn, and then I'm going to be done for the evening." And the next thing you know, it's 4:00 a.m. And I think that sometimes applies to fixing one more failure, just getting one more file in that chain of figuring out what the bug is in code. It's a very similar feeling. STEPHANIE: Yeah, I know exactly what you're talking about. MID-ROLL AD: Debugging errors can be a developer's worst nightmare...but it doesn't have to be. Airbrake is an award-winning error monitoring, performance, and deployment tracking tool created by developers for developers that can actually help cut your debugging time in half. So why do developers love Airbrake? It has all of the information that web developers need to monitor their application - including error management, performance insights, and deploy tracking! Airbrake's debugging tool catches all of your project errors, intelligently groups them, and points you to the issue in the code so you can quickly fix the bug before customers are impacted. In addition to stellar error monitoring, Airbrake's lightweight APM helps developers to track the performance and availability of their application through metrics like HTTP requests, response times, error occurrences, and user satisfaction. Finally, Airbrake Deploy Tracking helps developers track trends, fix bad deploys, and improve code quality. Since 2008, Airbrake has been a staple in the Ruby community and has grown to cover all major programming languages. Airbrake seamlessly integrates with your favorite apps to include modern features like single sign-on and SDK-based installation. From testing to production, Airbrake notifiers have your back. Your time is valuable, so why waste it combing through logs, waiting for user reports, or retrofitting other tools to monitor your application? You literally have nothing to lose. Head on over to airbrake.io/try/bikeshed to create your FREE developer account today! JOËL: So it can be really frustrating when you're kind of chasing down a bug because something's gone wrong, and now you're spending a whole afternoon figuring out where it is. Do you ever find yourself maybe acting preemptively to try to prevent those sorts of things from happening in the first place? So maybe putting in some sort of guards or error handling or something like that so that your future self won't have to spend that afternoon. STEPHANIE: That's a great point because the bug that I was facing just now was definitely something I think could have been avoided. It was a classic no method [laughs] on nil class error. And I am still unsure how that happened, and I hope to come back to it after this. But yeah, that certainly is a great topic to get into, error handling. I think it's been on my mind a little bit lately because I'm working on a full-stack feature that has user-facing errors and things we want to make sure that we communicate to the user so that they could hopefully do something about it or just contact customer support on this app. But there are also some API calls that are kicked off in the process of the user submitting the form, and those can lead to a bunch of different failures. And we may or may not have already discovered what those failures could be, and there may or may not have been designs created for those different failure states. And I feel like I haven't quite gotten a handle on how to deal with all of the possible errors that can happen when implementing a full-stack feature or a vertical slice. Yeah, that has tripped me up a lot lately. JOËL: I think my time working in Elm has really made me much more aware of the different ways that things can fail just because Elm's type system is very robust. It's very complete. And so it will point out to you every potential place that could have a failure and ask you to handle it because it doesn't want to get to a point where it doesn't know what to do and there's a runtime error for something like no method or something like that. So if you've got a potential nullable value and you're trying to say, okay, take this and render it, the compiler will say, wait a minute, you did not handle the null case. Give me something to do with the null case, or I refuse to compile. And now you've got to handle that. If there's something that might feel like an HTTP request, again, the compiler would be like, well, but what about the failure case? You didn't tell me what to do on the failure case. This is an incomplete piece of code. I refuse to compile that. So I think I've built now a little bit of anticipation because I know the compiler is going to tell me to do this. Now even when I write code that's not compiled like Ruby, my brain compiler is still like, oh, there's a nullable value here. You didn't check the null case. What are you going to do about that? STEPHANIE: Yeah, that's a great point. I think the more experience I gain, the more possible errors I see in the world or out in the wild. When I think about developing on the web, you know, you mentioned HTTP requests, but also, if we fail to connect to the database or a job fails to enqueue, there are just so many places where things can go wrong. And it's almost like the more I learn about all those possible failures, the more anxious I am [laughs] to make sure that I've covered everything though I think there is some amount of just that being impossible. And I'm particularly interested in figuring out what is enough because one thing that really I find quite painful is when you don't think through things enough and you just cross your fingers and hope it works and you ship it, and then your team is dealing with a lot of bugs or a lot of noisy error monitoring notifications afterwards. And so that's kind of what I'm trying to adjust for, I think. JOËL: I think there's like two general classes of approach you can use to deal with that; one is to try to prevent errors altogether, and there's a variety of tools you could use for that. I'm thinking of either something like a type system or maybe test-driven development or even some sort of analysis tool. That could be diagramming, that could be decision tables, something like that. All those, I think, fall under better understanding of the edges of your system. Whereas sometimes you want to do the opposite and sort of really lean into, okay, errors will happen. How do we recover from them? How do we make them easy to diagnose in the future? STEPHANIE: Yeah, that second bit is really interesting to me because I've started to try to think about the errors and who we want to notify about the errors. And so I feel like there are a few different categories of errors where if it's a validation error and it's something that the user can fix, you know, that we want to make sure to surface and tell them how they can fix it. If it's like a programming error, there's no value in showing that to the user. And I'm sure that we've all seen a website that responded with a 500, but then we actually saw the error message itself, and we're like, ooh, this is kind of weird [laughs] to be seeing this. And so realizing, okay, that's not valuable to the user. But what should I be doing with it instead? And maybe that is hooking it up to whatever error monitoring service you use to make sure someone is alerted. Or, I don't know, even in the third case, like, what should a customer support team be notified about? And that kind of sits in between not quite a user-facing error but also not a bug, and that's a different category. JOËL: So, something that is not necessarily a problem in the code, but you might want somebody in the company to know about and be notified about. STEPHANIE: Yeah, exactly. Maybe not something that is so urgent that it needs to be flagged in real-time but goes somewhere, and someone will check on it at some point. [laughs] So you were mentioning that you now have a better sense of what could go wrong. How much time do you spend writing code to cover all of those different possibilities? JOËL: Hmm, I don't know that I've ever put the time to quantify it. I would say a decent amount because you've got to think about...sometimes they're not even things that can go wrong per se. But they're off that very simple, linear happy path that you're thinking of. So you might think even for rendering some kind of view, and you've got some search results you're trying to display. Have you considered an empty state? Is there a difference between initially loading the page or have not performed a search yet, and search but did not find any results? Those are things that are not necessarily errors, but they're not things you're thinking in mind when you're just writing that first happy path of, like, oh, load page, show results. I assume there's always a result set. And so those are things that are important for the user experience that you need to have, but that are kind of edge cases that you have to add in afterwards, or you have to think about. And so I think that, for me, tends to fall under a similar category as okay; what if an error happened? Especially when you're dealing with kind of a full-stack situation where on the front end maybe you're making a result to a back end to pull down...let's say you're making a search and the back end is doing the actual search. You send up a query. Now you get back a failure. Is that the same thing as getting no results back? Like, a success with no results, versus an error code, versus not making a query yet. So you've got like four or five states you've got to think about on the front end to display and how you're going to handle those. So I think thinking about those upfront is often really helpful. STEPHANIE: As you were talking about that, I suppose I asked the question because I have experienced when those things are not thought about upfront, and then you discover them as you're implementing. And how much time do you use to kind of go into a little detouring trying to make sure that you have all of the edge cases covered, and at what point do you stop? Because you're like, I've covered what I can. And this ticket was supposed to only be three points [laughs] or whatever, you know. JOËL: Yeah. And how do you keep a feature from ballooning when there are all these edge cases? STEPHANIE: Yeah, exactly. It's a balance. JOËL: Are there any techniques that you like to do when you...so you pick up a ticket that looks easy, but that might have a lot of these hidden edge cases in it. Are there techniques you like to use that might help you figure out those edge cases and maybe give you some follow-up questions that you might reach out to the product person to clarify? Or maybe it's mostly intuition and experience as a developer that you kind of figure out that, oh, these are the things we need to ask about. It's like, have you thought about an error state? STEPHANIE: Yeah, that's a good question. In general, I'm a little suspicious of any ticket that doesn't include some kind of acceptance criteria about the unhappy path. And I certainly think it's a lot easier once you are embedded into this domain, and you have that expertise, and you are able to see the possible issues you'll run into. I do think that I like to do a little bit of coding just to kind of explore the space, and then that does give me more insight into how I might be able to follow up on the ticket. So you mentioned techniques. Especially if they're written as user stories, I don't think they necessarily incorporate the flow or the procedure of how things are kicked off. And so when you're thinking about implementing it, you're like, oh, this actually needs to happen in the background, or this should be synchronous or not. And those are a lot of error states that I find are missing when I pick up a ticket. And I think it also depends on which way you want to implement it what implementation is viable. And then maybe you bring it to a product person, and they are actually like, "No, we don't want it to work like that." And then you have to kind of rethink things a little bit. But yeah, certainly, the process of taking a user story and then doing an initial think-through of what approach you want to take definitely surfaces some potential unhappy paths. JOËL: It's almost like prototyping it in your mind. STEPHANIE: Yeah, I think so. I think it also depends a little bit on the team because if the engineer wrote the ticket, then there likely has been some thought about unhappy paths. But on other teams that I've been on when implementation is up to the person who picked it up rather than kind of spelled out for you by someone else who did that thinking, that's definitely an opportunity to pause, I think, and document which way you might want to go so that you can make sure that you account for the possible things that could go wrong that likely the user story didn't cover. JOËL: Sometimes there are some edge cases or failure states that are just sort of built into the problem that you're solving. If you're having to make a background request, there's always a chance that that might fail because the network is not trustworthy. Sometimes though, those things just kind of come out of our implementation, the fact that we implemented it in a particular way. And that's not something that you'd expect a product person to have to think about. That's more on us as developers to be like, oh yeah, well, I'm indexing into a hash and didn't think to check is a nested hash even present? Maybe that key isn't there. And now I've got a weird nil error, an undefined method. That's kind of on us rather than on, like, oh, a specific kind of thing that we can think about upfront. STEPHANIE: Yeah, that's fair. And I think that is just an important part of the development process. Though you make a good point because I think that just kind of speaks to all of the different layers of things that can go wrong [laughs] and figuring out which ones are specific to your role as developer to account for, and then which are ones that you need to bring in or pull in a designer to chat about. It can be a little overwhelming. I'm overwhelmed just thinking about it. [laughter] JOËL: Yeah, errors are not a sort of monolithic class of things. They can't be an afterthought. But they're also not just a thing where it's like, oh yeah, do the error handling, and then you're good. We kind of lump a lot of things under the concept of errors, even if they might all eventually manifest as some kind of exception. I guess a true solution is just one giant top-level rescue nil. STEPHANIE: [laughs] Very funny. JOËL: So we've talked about a few different dimensions of errors where they might be sort of user-visible or not, or something that's more implementation-based versus inherent to the problem. One thing that we haven't looked at is the dimension of errors that might be recoverable versus not. Have you ever built a system where you had errors that could be recovered from and didn't crash the program? STEPHANIE: Ooh, yes. That makes me think about retrying and especially what you're saying if things are happening in the background. Maybe there is an ephemeral error where the network timed out or something. But if it is given another shot, it might succeed on the second go. And I think there's a whole process of thinking about what happens when a process has to be retried and if there were any side effects that you didn't want to have committed the first time around, you know, but then something else that was supposed to happen and when the process happens again, things are very broken. So making sure that you are keeping things idempotent so that by undoing it again, there are not any unforeseen issues. JOËL: I heard you say that word commit here, and that's kind of a keyword to my mind. I immediately think database transactions. Is that the sense that you're thinking about this term here? Or does it have another meaning for you in this context? STEPHANIE: Yeah. I do think I used that word specifically because when I've run into this in the past, it has been around making database changes. I'm trying to think if there is another way that this might show up. I think even in something like sending an email, too, though it is a bit lower stakes. I've certainly, as a user, experienced when that goes wrong and just been [laughs] flooded with emails and being like, wow, this is annoying. And that's, I think, something valid to consider as well. JOËL: Yeah. You don't want that email job to be a thing that gets retried and just keeps failing because there's a nil error after the email gets sent. And so we just re-enqueue it, re-enqueue it, re-enqueue it, and the person ends up receiving 500 emails. STEPHANIE: What about you? Any thoughts about recoverable errors? JOËL: Yeah. I think really common for me is thinking about that in the context of a background job because those are things that I think are specifically designed to be retried if they fail; at least, a lot of job enqueuing systems assume that. When we write them, we don't always take that into account, but that's the system that we're working in. So that can be something as simple as marking somewhere that you have sent that email so that you don't resend it if that job ever re-executes. I think that goes to your point about idempotency earlier that you often want to write code that can get executed multiple times but doesn't necessarily do the action multiple times. It will do it at most once. And that's probably an interesting distinction to have is knowing what elements of your code need to execute at most once, versus as many times as the code is called, versus things that might get tried and then rolled back like a database transaction. And so then that will...I guess you could say it's at most once because you're writing it but unwriting it. But that plays out a little bit differently than something like an email where you can't undo sending an email outside of Gmail. STEPHANIE: Yeah, I love that undo button. [laughs] JOËL: You need some other mechanisms for that. STEPHANIE: Yeah. As you were talking about that, I was also thinking about the idea of failing gracefully, which I think also ties into the idea of recoverable. So this is not a development-specific example. But the idea of an escalator no longer working well; at least you can use it as stairs. So that doesn't mean that everything is totally broken and people are unable to get from one floor to another. So maybe if there is a network request that's touching data and that fails, you can at least fall back on something that's cached. That mindset, I think, really is important to think about at all the different levels we are talking about. JOËL: Yeah, or hopefully, even maybe some amount of graceful degradation. On a front-end app, you might not want to just crash the whole thing if one background request failed. So you can try again. You can be told, okay, try again in so much time. Maybe we automatically retry to make that same request with some sort of exponential backoff strategy. Or maybe we say, "Look, search is down for now. Here's a link if you want to go check a status page. Until then, other parts of the site are still working." I feel like we're getting back into what makes great product design and how great product designers have to make failure conditions. It has to be at the forefront of the thinking that comes to designing that product. STEPHANIE: Yeah, that's a good point. I think my initial feelings of being overwhelmed and stressed about dealing with errors may be because a lot of it falls on the developer if those things aren't accounted for. And we spoke a little bit earlier about, okay, what is within our realm or domain of actually being responsible for, and what can we loop in others for help with? JOËL: So we've been talking a lot about different ways of preventing errors, different ways of recovering, generally trying to make the whole experience really smooth. A slightly different philosophy around errors is rather than preventing them early is to fail early, like, fail early and loudly. And maybe you recover, maybe you don't. That depends on the context. But instead of putting so much effort into preventing errors upfront, it's better to just crash a lot or to fail loudly and deal with the consequences, or have a strategy for dealing with failure because failure is inevitable. How do you feel about that philosophy? STEPHANIE: Oh, I think it has a time and a place. One example I'm thinking of is if you don't want your application to be deployed if some configuration is not exactly how it needs to be for the app to run effectively. And so there is a matter of, like, okay, I really want to make sure that the DevOps team or the development team knows that something is very wrong because if this were to be deployed, the app would be unusable. And so that's an example to me of failing loudly but, ideally, not letting it affect end users because they're still using [laughs] the site on a different version. [laughs] JOËL: Right. I guess the classic example of that is for a Rails app, doing a Hash#fetch() on the environment to load up your environment variables instead of using the square bracket syntax so that as the app is booting and executing those initializers, it will crash if it encounters one of those and then fail to deploy if you're doing a deploy via something like Heroku. I've even sometimes when I'm adding environment variables, purposefully had them loaded in an initializer rather than maybe like in a class later on, specifically so that it would crash the app and prevent deployment if that environment variable was not set. STEPHANIE: Yeah, that's what I was thinking too, environment variables. Though I think even with that kind of mindset, you're either just delegating that responsibility to someone else down the line to either figure out how to accommodate or account for in a graceful manner. Or you are creating an environment where everyone is very stressed out [laughs] and having to fight fires. So I think it also requires a little bit of thought and isn't necessarily a strategy to just completely embody. [laughs] JOËL: I've noticed that bugs and errors often accumulate at the boundaries of systems or even subsystems or modules within a program. Maybe the place to apply the strategy of failing early and loudly is particularly valuable at those boundaries. But internally, within a subsystem or a module, maybe it's nicer to use other strategies for error handling. Does that sound like maybe a useful distinction to you? STEPHANIE: Yeah, I think subsystems was the keyword to me there because you don't want it to be such a catastrophe that it affects the usability of the app entirely. But that does still require some systems in place, I think, to respond to when that thing is failing loudly. JOËL: I think an example that came to mind for me is like you were mentioning earlier, a full-stack application. And if you've got the back end that's providing an API and something is wrong, I don't want that API to give me back garbage data and try to pretend that everything's okay. Let that API give me back some kind of error code. And I in the front end, I already know that the network is inherently unreliable. I'm planning to handle errors at that point. So it's fine for the API back end to fail loudly in this case. In fact, I think that's the optimal solution. STEPHANIE: Yeah, I think that's true because ideally, that error clues you into what kind of thing failed, and then maybe you can use that information more meaningfully than trying to guess at what happened with this bad data and then having to define some kind of error message in your app when ideally someone else who had more knowledge about it could have told you what went wrong. JOËL: And I guess the problem with not failing loudly or with an explicit failure is that if you try to just pass on some sort of value that will pretend to be like what you initially asked for, whoever's consuming that doesn't know that something went wrong. So then you use this garbage data, and you do some things and pass it along to the next person. And eventually, it may cause a failure three or four steps down the line. And now, trying to trace that, like, why did this fail? And it's not because something was wrong in Module D, or C, or B. It all comes back to oh, A had a problem but didn't crash or give us an error. It tried to pass its sort of best guess, like, this is probably okay. And then it just kind of moved all the way down the line. STEPHANIE: I'm imagining external API developers everywhere just nodding their heads in agreement. [laughs] JOËL: I've fought this on a local level as well. I was working on some kind of code for a JavaScript date picker plugin, and this was back in the jQuery days. It was some kind of...it was not a date picker. I think it was a typeahead drop-down thing. In some situations, I forget exactly how it would happen, but the input from there might be empty, but then that would get converted into an undefined value, which then JavaScript would convert to the string undefined, which would then get passed to something else that if it saw a string, it thought that was the thing that the user typed, and they would pass it through. And I think maybe in the end, I was looking at a crash ten functions away in the front-end code that had to deal with the input from this typeahead and being like, why am I getting these undefined? Or maybe it was a string NaN or something like that. Like, why am I dealing with these weird strings that should never have come out of this? And it turned out it was just kind of an edge case. It wasn't addressed in this component further on, and then it was kind of leaking strings that everybody else thought was sensible up until three or four jumps further down the stack. STEPHANIE: Yeah, that's a great point. I think it does go back to the idea of there being preventable errors. And then there are things that are truly not preventable because we live in a physical world [laughs] where computers talk to each other over the wire. And that distinction is, you know, perhaps the first being avoidable errors by writing resilient code. And the second being like, okay, in reality, there will be things that go wrong, and this is what we really have to watch out for. On that note, shall we wrap up? JOËL: Let's wrap up. [laughs] STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.
Stephanie has a win and a gripe from her client project this week. In a previous episode, Joël talked about his work exploring how to model dependent side effects, particularly D&D dice rolls. He went from the theoretical to the practical and wrote up a miniature D&D damage dice roll app that you put in a few inputs. Then it will roll all the dice necessary and tell you did you successfully hit your target and, if so, how much damage you did. Together, they discuss how they think about fulfillment at work and what brings them fulfillment as developers. Obsidian (https://obsidian.md/) Joël's DnD dice roll app production (https://dnd-damage-roller.netlify.app/) site and repo (https://github.com/JoelQ/dungeons-and-dragons-damage-calculator) Engineering Management for the Rest of Us (https://www.engmanagement.dev/) The Five Love Languages (https://www.psychologytoday.com/intl/blog/click-here-happiness/202009/what-are-the-5-love-languages-definition-and-examples) Transcript: JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. STEPHANIE: And I'm Stephanie Minn. And together, we're here to share a bit of what we've learned along the way. JOËL: So, Stephanie, what's new in your world? STEPHANIE: So I have a win, I suppose, and a gripe from my client project this week that I would love to share. So my win is that I've been working in React lately. And I might have mentioned this on a previous episode, but it's been a few years for me. So I'm kind of catching up on the new, hot tooling, you know, whatever is popular in that world these days, and having to read a lot of documentation to figure out how to use it and just in general, I think being a little bit outside my comfort zone. And I was working on an existing React component that was untested, and I had to change and extend some functionality in it. And we're also a little bit on a deadline. So there's like a little bit of pressure on the team to be delivering. And so when I got this ticket, I was like, okay, I am seeing this existing component that looks also a few years outdated. It's using some of the older technology that we've kind of moved on from. And I was just like, oh, I really should write tests for this before I go in and change some things just to feel confident that my changes don't break anything because it was pretty gnarly. But I was not in the mood for it. [laughs] And this was like two or three days ago. I was just very grumpy. And I was like, oh man, why do I have to do it? [laughs] I kind of wanted to just get into making the changes so I could deliver on this work. So, spoiler, I did not write the tests that day and just kind of went ahead with the changes. But then, the next morning, I woke up, and I was feeling inspired. I was like, I made those changes, but I'm actually not feeling that confident about it. So let me go back and try to write some tests. And I got to use the new tools I had been looking into, and that was part of my hesitation too. I was like, oh man, this is like a really old component. And I don't want to use the older ones that we're using for testing. But how is it going to play with the newer testing tools that we're using? And so there was just like a lot of, I think, barriers to me feeling excited about writing those tests. But with my renewed energy, I did it. And I feel very happy about it and proud of myself. Yeah, that's my little win. JOËL: That's a roller coaster of a journey there. That sort of deception when you find out that there are no tests for this and somebody else's problem has kind of become your problem. But then you decide you don't want it to be your problem, you know, kick it down the road for somebody else. And then you feel good about yourself, and you decide to backfill the test anyway. And you get that confidence, and now everything's better for everybody. That is quite the journey. STEPHANIE: Exactly. I listened to another podcast recently where they coined this term called tantrum logic, which is basically the idea that when you're kind of grumpy or something happens, and you're like, man, I don't want to do any of this, like, if I can't do it my way, then I don't want to do it at all. [laughs] And just the idea that the way you're thinking about the issue at hand may not be totally grounded in reality. And I think I needed that reset and just a good night's sleep and going to do something else to come back and be like, actually, I do want to write those tests, even if it will be challenging. I'm in a better mind space for it. Mind space? Headspace? [laughs] Headspace for it. And I overcame the tantrum logic. JOËL: A good night's sleep is just such a powerful tool for resetting. STEPHANIE: Yeah, I agree. Shout out to sleep. [laughs] It turns out that it can really have a positive effect on how you feel. JOËL: By the way, this is not an advertisement. We are not sponsored by sleep. We just both love it and recommend it. STEPHANIE: [laughs] To get into my gripe a little bit, so you and I are on the same client project we've mentioned before on the show. And I think I even talked a little bit about receiving a new computer from our client to do our client work on. So now I have many devices at home. And we had also chatted previously about a note-taking app that we both use called Obsidian. And one of the reasons that I really like it is because it's all local storage. So your notes are not being uploaded to the cloud or whatever. But that does make it hard to use on multiple, I mean, not just hard, impossible to use [laughs] on multiple devices unless you pay for it. They have a sync offering where you can use it on multiple devices. And I think it's also encrypted in a certain way. Anyway, sometimes I'll be working on my client laptop and have some idea or thought that I really want to note down, but I don't have Obsidian installed on this machine, and it's not synced to my other Obsidian. And I have just been kind of annoyed about having to go open another computer to write a thought down if I want to document it. And I'm curious how you deal with this problem. JOËL: So the downside of Obsidian not being a cloud product is that you don't just get that sync for free. The upside of it just being markdown files on your hard drive is that you can use any other product or tool that you want to manipulate these files. So I have my Obsidian vault, which is just the term for the directory where it keeps all of these files in a Dropbox directory. And so I have it sync across multiple machines just by being signed into my Dropbox account. STEPHANIE: That's smart. And that sync is pretty smooth for you? You don't have any issues with updating it in one spot and seeing those changes in another? JOËL: I have not had issues with that. Of course, I'm not jumping between machines within 30 seconds of each other. Generally, I'm also connected to the internet. So I haven't had a situation where I make a change to a machine not connected to the internet, and then later on, I edit an old version on a different machine that is connected to the internet, and now we have conflict. I've not run into that problem. STEPHANIE: Okay, cool. That sounds good. It's funny you mentioned that because it's just the other day, off-mic; you and I were on a call doing a little bit of pairing. And you were on both machines at the same time [laughs] because we had to use one for our call. And then you were looking something up on your client computer as well. And the thought of you just using two computers at once was very amusing to me. JOËL: It's the ultimate hacker move in...I was going to say bad, but that's maybe a little bit too judgmental, but yeah, in classic, I feel like police shows, things like that. STEPHANIE: I do have one more thought about note-taking that we haven't talked about before. But I'm really curious, how do you deal with thoughts you have on the road during a time you don't have a device on you? Do you go and write that down somewhere, or what do you do with those? JOËL: I have an absolutely awful solution, which is I add it to my mental stack and hope it doesn't overflow before I get to a computer. STEPHANIE: That's really funny because I used to do something similar where if I had a to-do list or something like that in my head, I would remember the number of items on my list to try to cue me into remembering what those items were. The worst thing that would happen is I would remember that I had three things on my to-do list but could only remember two. And so I had to just [laughs] deal with my existential anxiety about knowing that there was something else that I had forgotten about but could not remember [laughs] for the life of me what it was. JOËL: So I do that trick sometimes for my grocery list if I don't want to write it down. I'll just be like, oh yeah, go to the grocery store, make sure there are five items in my basket when I check out. And similar to you, sometimes I have that problem. I had a light-bulb moment the other day, which is that this trick is actually an example of hashing content. STEPHANIE: [laughs] JOËL: So if you're ever hashing the contents of a file and then wanting to compare if another file is the same and you check the hashes are the same. In a sense, you're kind of hashing your grocery list and your shopping cart and trying to see do they both hash to the same value? Now, a good hashing algorithm has an infinitesimally low chance of a collision. Counting the number of items in your list or cart has a fairly high chance of a collision. You could have a cart and a list that both have five items, but they're not the same items. Yet this comparison would still make you think that they're the same. STEPHANIE: This is a very funny metaphor to me. I think the other issue is that as a human and not a computer, I do not have the mental storage space to then also remember what algorithm [laughs] I'm using to hash my to-do list. JOËL: The algorithm is the count function. STEPHANIE: [laughs] True, true, a more sophisticated algorithm then. [laughs] JOËL: Yes, which is why I keep using this not very safe, but it's good enough. STEPHANIE: Sometimes, we just need to be good enough. So, Joël, what's new in your world? JOËL: So, in a previous episode, I think we talked about some work I was doing exploring how to model dependent side effects, particularly D&D dice rolls. So this week, I went from the theoretical to the practical and wrote up a miniature D&D damage dice roll app that you put in a few inputs, and then it will roll all the dice necessary and tell you did you successfully hit your target, and if so, how much damage did you do? And it takes into account all these edge cases. STEPHANIE: Cool. That's so exciting because I think we mentioned last time how that would be a really interesting exercise to write up that code. Did you get any insight from doing that? JOËL: I think a lot of the insight that I got came from the initial diagramming phase. And I think coding it out really solidified the things that I had learned from the diagramming. Of interest here is that there are effectively or potentially four separate dice-rolling phases that can happen. First, you're rolling to see can you hit your target? And depending on the situation, you're rolling one or two dice. And then after that, you're rolling to see if you do hit, how much damage you do. And you're either rolling one set of dice, or you might be rolling two sets of dice if you happen to do a critical hit. So I think that the diagram that I had clearly showed these are four sets of randomness that have to happen and then how they relate to each other. These two are dependent on each other; these two are independent. I think one thing that was really interesting that I learned from the code is that for something like a dice roller, you usually don't want to see just the result. Because if I just have a button that says how much damage did I do, and then I get a number back that says, "You did zero damage," or "You did three damage," as a person, that's not very satisfying. And I don't know that I fully trust it. I want to see all the intermediate results. So I want to see, oh, did I roll two different dice for that initial two-hit? What were the numbers? And then I can say, okay, well, I need to roll above a five or roll above a 10. And I rolled these two dice, and they were both under 10. That makes sense why I didn't hit. Or I rolled one of them above and one of them below, but I was rolling with disadvantage, which means I have to take the lower of the two numbers. So I could have hit, but I didn't. So I think that is really fun as a user to see the intermediate steps. But also, as a developer, it helps me to be confident that the code I wrote works the way I expect it to. STEPHANIE: Yeah, that's really neat. I think what I love about this is that you took something that, in some ways, could be really simple, right? And the implementation could have been just the first thing that you thought of, but you thought very deeply about it and made the dice roller that you wanted in the world. [laughs] I'm curious. Can anyone go check out this repo on the internet? JOËL: Yes. So we can link to the repo in the show notes. And also, the dice roller itself is up online at dnd-damage-roller.netlify.app. And we can link that as well for anybody who wants to go and check it out. STEPHANIE: Awesome. JOËL: I think my goal in this is it's more of a learning exercise. I don't think the world needs another D&D dice roller. There are better ones built into more comprehensive tools. But it was fun for me to work on this, to explore some ideas, and to dig into randomness. I've always had a fascination with random rolls. MID-ROLL AD: Debugging errors can be a developer's worst nightmare...but it doesn't have to be. Airbrake is an award-winning error monitoring, performance, and deployment tracking tool created by developers for developers that can actually help cut your debugging time in half. So why do developers love Airbrake? It has all of the information that web developers need to monitor their application - including error management, performance insights, and deploy tracking! Airbrake's debugging tool catches all of your project errors, intelligently groups them, and points you to the issue in the code so you can quickly fix the bug before customers are impacted. In addition to stellar error monitoring, Airbrake's lightweight APM helps developers to track the performance and availability of their application through metrics like HTTP requests, response times, error occurrences, and user satisfaction. Finally, Airbrake Deploy Tracking helps developers track trends, fix bad deploys, and improve code quality. Since 2008, Airbrake has been a staple in the Ruby community and has grown to cover all major programming languages. Airbrake seamlessly integrates with your favorite apps to include modern features like single sign-on and SDK-based installation. From testing to production, Airbrake notifiers have your back. Your time is valuable, so why waste it combing through logs, waiting for user reports, or retrofitting other tools to monitor your application? You literally have nothing to lose. Head on over to airbrake.io/try/bikeshed to create your FREE developer account today! STEPHANIE: So it sounds like the Dice Roller app really scratched an itch for you and was a fulfilling exercise for you and just exploring randomness, like you mentioned, and just a theory that you had about writing good code. I'm curious about how you think about fulfillment at work in general and what brings you fulfillment as a developer. JOËL: Fulfillment is really interesting because I think it's a really kind of personal question. It probably varies a little bit from person to person. But there are probably also some aspects that are global to everyone. I know we've talked about things like psychological safety in the past. And if you don't have things like that, that baseline, it's going to be hard to feel fulfilled. STEPHANIE: Yeah, I agree. I am thinking of Maslow's hierarchy of needs, and in some ways, fulfillment is kind of the tip of the pyramid. If you are feeling safe and like you belong and get enough sleep, like we mentioned earlier, you can reach towards getting into what really feels fulfilling and gives you purpose in life. JOËL: I love that you brought up Maslow's pyramid because like you said, that top part is self-actualization. So you need all those lower layers before you can actually reach the point of true fulfillment on the job. One thing I recently realized about myself is how I tend to approach projects that are in a difficult place. I find a lot of fulfillment in sort of relative change. It doesn't matter if a project is in a bad place as long as the project on a week-by-week basis is moving in the right direction. It might still be in a bad place, but is it better than last week? And was I a part of making that better? That makes me feel good. STEPHANIE: Yes. I have always really admired your optimism around that and how you share even small wins. You're really good about that, actually, and celebrating that. And it's interesting to learn that it's like that process itself that has a lot of meaning for you. Because I think I'm a little bit different in the sense that I have an ideal version of working in my head, and if we're not there, even if we are making some incremental progress week to week, I think I struggle. Sometimes I feel frustrated or stressed because I think that we're just not where I want to be. And I've definitely been thinking about harnessing some of that optimism and celebration that you have around, just making things better a little bit at a time. JOËL: And I think we should be clear that this is not the way one has to be; this is just how I tend to feel on projects. STEPHANIE: Yeah, absolutely. JOËL: I know there are plenty of people who feel most fulfilled when they're on projects where things are mostly good. And then it's not about incremental improvement in the product, but maybe it's shipping a lot of features and feeling like they're moving very quickly. Maybe it's that feeling of speed that gives them fulfillment rather than the feeling of incremental progress. STEPHANIE: Yeah, absolutely. I think what is helpful for me in hearing about this from you and just from others (I love talking to other people and learning about what motivates them.) is seeing what else is possible outside of my own little universe inside my head and doing the self-reflection to be like, okay cool, this works for Joël, but maybe this doesn't work for me. But having the input from other people lets me discover more about myself in that way. JOËL: That is incredibly powerful. I love that. I think in a variety of aspects of my life, but especially when it comes to fulfillment in software and at work, talking to other people, seeing how they relate to a project or to a particular task, and, like you said, getting to see their perspectives that are sometimes totally different than mine. STEPHANIE: Yeah, absolutely. So you just mentioned one aspect of how you find fulfillment when a project is maybe in a tougher spot than usual. I'm curious if you can recall a time that you've been the most fulfilled at work. JOËL: Most fulfilled. I think one of the most fulfilling projects I did was several years ago. We built a dashboard for just exploring a lot of data from medical studies. And so the researchers would upload some time series data for things like heart rate, or skin electro-sensitivity, a bunch of other things, along with a video. It was a kind of an interview-style situation. They were doing a session with a patient. And we would then sync all of these data streams up. We would sync it up to the video, and then you could kind of explore the data. There were scrubbers, so you could kind of scrub through the video, and it would scrub through the time series data all at the same time in sync. You could scrub through the time series data. It would sync the video kind of like bidirectional. You could zoom in on the data. The idea is this is a high-level kind of exploratory tool. And you could then find the interesting bits of data that you could then do more quantitative analysis on. So you could then find a part of the stream and say, this is the interesting part. Clip from 10:55 to 11:10 in the stream, on all streams, and then export just that data in a zip file. And then I'm going to put that through a bunch of math and figure out, oh, is there a correlation between these moments? STEPHANIE: So what about that project was really exciting or fun for you? JOËL: I think the client was incredibly fun to work with. There was like an energy and excitement. This was part of their, I think, Ph.D. thesis. And they were really excited. They were incredibly knowledgeable, just delightful to work with. I think this was a fun...so we built this from scratch. It was a greenfield app. I think it had a lot of interactivity. It had a lot of visuals. It was one of the first projects I got to work on that used Elm. I think all those things combined to just make it a really fun project to work on. It was also a fairly short project. So we had a very kind of tight deadline. We were very pragmatic with absolutely everything on there. Like, what can we do to get this done quickly? Is this feature worth the time? It was kind of a classic MVP product. And I think it was one of the most fun things I've built. STEPHANIE: Cool. I'm also hearing there was probably some creative aspect of it that was really fulfilling for you, like exploring a lot of new things. Like, you said, you were working with Elm for the first time. And the project itself sounds very different from some of our other more typical consulting engagements and also the collaboration aspect. Like, you mentioned the tight deadline, which compelled you all to work really closely together to make this really cool thing in that short amount of time. JOËL: Exactly. Yeah, it was like a three or four-week project that I look back on really fondly. Like, oh, that was a good time with those two colleagues and that client, and we did a thing. It was really cool. STEPHANIE: That's awesome. JOËL: I think it's really interesting that just hearing that story, you're immediately picking up on, like, oh, I see elements of creativity and exploration. Do you have kind of an internal system that you use to analyze projects that you're on to be like, oh, this is a project I'm enjoying because of this element or that? Because you seem very self-aware around these types of things. STEPHANIE: I'm glad you asked that because I think I was trying to reflect back to you some of the things that I picked up about what you were sharing. I have been reading a book, surprise, surprise. JOËL: What? You read? STEPHANIE: I read. [laughs] It's called "Engineering Management for the Rest of Us" by Sarah Drasner. And I am not an engineering manager, and I don't necessarily know if I even want to be. But I really enjoy reading management books to better understand how to manage myself or how to be a person who is managed. And one of the things she talks about is understanding an individual's values and how those things end up being what motivates them and also likely what brings fulfillment. And so after I learned about the value of values, I started thinking, okay, what is it that I am motivated by? And really reflecting on when I have felt really good about work and also when I felt challenged or unhappy at work and what things were missing during that time. So the things that I have realized that I am very motivated by are human connection. I love spending quality time with people, and that is probably why I enjoy pairing so much. But also, in my one on ones with my manager, I really enjoy that time just being time for us to share space and get to know each other and talk. It doesn't necessarily need to be going through agenda items or a status report or even necessarily talking about my project. JOËL: So you mentioned that you value quality time with others. Is that a reference to "The Five Love Languages" concept? STEPHANIE: It is. It is. I think I also made a bit of a connection there too because what I like in my personal relationships also obviously applies to work. JOËL: Yeah, it's how you feel appreciated, how you feel fulfilled. And just for our listeners who may not have read this book, I think the concept is that there are five ways that people like to receive appreciation. STEPHANIE: Yeah, I think receive and both express appreciation and love. And quality time is one of them. JOËL: Yeah, yeah. And the other four, if I remember correctly, are acts of service, words of affirmation, physical touch. STEPHANIE: Gift-giving is the last one. Yeah, so that was a fun reflection on my part in being able to just know what makes me feel good. And then it also helps me communicate with other people how to work with me. I think that is super important. I love when people share with me what, I mean, I mentioned this earlier, just what drives them and how they like to be appreciated so that I can do my best to try to offer them that. And I guess this actually is a good transition into the next value of mine that really drives me. I was thinking about this because I mentioned just now that I was learning some new React tools, new to me, anyway. And I'm like, yeah, I like learning. But then I was like; I don't know if I like learning the way other people like learning in the sense that it's not the knowledge itself or the process of learning itself that drives me but learning as a tool to better understand myself. So I think personal development is very important to me. And that feels different from how other people might value learning. JOËL: Interesting. So you might be excited to learn a new React testing tool but not because you're chasing the latest, shiny tech but more because you feel like the process of learning this testing tool helps you learn something new about yourself. STEPHANIE: Yeah, I think that sounds right. One of the tools specifically...we're using MSW Mock Service Worker for mocking network requests in Jest. And I was able to use information about testing in Rails and Ruby and apply that to this new tool. And I got to kind of revel in the fact that I could use previous learnings to apply in this new context, and that was really cool to me. So it wasn't necessarily the tool itself or even the process of learning but kind of realizing that I was capable of applying one thing to this less familiar thing. JOËL: So kind of that realization that, hey, you're now far enough in your career, and you have enough experience. You have a broad base of knowledge that all of a sudden, you realize, wait a minute, I'm not starting from scratch anymore. I can apply lessons learned in the past to learn this new thing and make that easier. And that's a really validating feeling. STEPHANIE: Exactly. That was really cool to me, and I felt really good afterwards. I think this week at work has been very uplifting because I've been having all these little mini-revelations if you will. JOËL: I love that. I love that so much. STEPHANIE: So, one thing that I think is very easily conflated with fulfillment is the idea of success. And I kind of want to talk about the distinction between success and fulfillment. Does that bring up any thoughts for you? JOËL: Yes. I think the two are often entangled, but they're definitely not the same thing. It is possible to be fulfilled on a project that is not successful. And it's also possible to be on a successful project and yet not feel fulfilled. But oftentimes, the two go together because when things are going well on a project, they're probably also going well in a lot of other ways, and you might be feeling fulfilled as long as general parameters fit in, right? If values line up, things like that. I know for me I value quality and excellence and doing work that I'm proud of. So I think if I were working at a place that was doing kind of low-quality, low-cost work where it's just like, you know what? You want cheap and low-quality? Come to us. We'll just get it done quick and cheap. And yeah, it's not going to be great, but you get what you pay for. There's a reason this part of the market exists, and it's a totally valid way to build software. But I would not feel fulfilled there, even though maybe the clients are absolutely happy with the work that's being done. So I think that would be a situation where there is success, but I might not feel personally fulfilled. STEPHANIE: Yeah, I'm glad you brought that up because I think I really struggled in the beginning of my consulting career with equating client happiness with success. And I'm now just starting to kind of unlearn that a little bit and realizing that success means different things to different people. So even if we talk about thoughtbot for just a second, one of thoughtbot's values as a company is seeking fulfillment in everything that we do. And so even though, like you said, the client might be totally happy, for thoughtbot, that may not be a successful client engagement if you, Joël, as the developer staffed on that project, didn't find fulfillment. Because what's success for us here is that we are fulfilled in the project itself. And that was really helpful because, in some ways, I'm like, well, who cares? Who else cares besides me that I'm fulfilled? And to be like, oh, yeah, actually, what our collective success means is that I'm fulfilled, and you're fulfilled. That was really important to me and one thing that I really appreciate about working here. JOËL: Fulfillment comes partly from our environment, from maybe the project that we're working on, our colleagues, but also comes to a certain extent from ourselves. And to a certain extent, we can drive that ourselves as well. And I think that first step is a certain amount of self-awareness and self-understanding. You are clearly a master at this. What are some things that you do to drive that self-understanding, to build maybe a sense of how you become fulfilled, and identifying those values that make you feel fulfilled on a project? STEPHANIE: Listen, [laughs] I don't know if I would call myself a master at this, only that I'm very actively working on it in my life right now, in therapy, but also in talking to other people about this because, yeah, sometimes it has caused me a lot of turmoil. I'll be really stuck in a rut or feeling a lot of burnout, and that, ironically, actually motivates me to be like, how can this be different? And oftentimes, that means I have to look inward. But you and I had a conversation last week off-mic that was really helpful for me because I was feeling really bummed about my client work and it not going the way that I thought it would. And your insight helped me think about the project a little differently and think about metrics of success differently. For that project, I could not expect that project to look exactly like all of my past experiences. And success for those projects were not the same for this project. So yeah, talking to others, I highly recommend that. JOËL: I guess you mentioned that you read a lot of management books and a lot of books geared towards managers for discussing things like how to set up a one-on-one. Those are almost like...they're not really therapy, but they kind of lean a little bit towards that sometimes and trying to create fulfillment for your direct reports. So maybe seeing it from the other side helps you build understanding. STEPHANIE: Yeah, actually, that's totally a great call out because I highly recommend reading books about [laughs] management, even if you're not interested in management. Only because there's no guarantee that you'll have a good manager who can do all those things for you, so if you can equip yourself for doing those things, then you are likely to have a better workplace experience, in my opinion. JOËL: And I guess the obvious one that we have not talked about is if you do have a good manager, have these conversations with them. STEPHANIE: Yeah, absolutely. JOËL: Part of their job is to help you be more fulfilled. And they should be having conversations to maybe help you discover those ways that you are feeling fulfilled at work and how to get there. Here's one aspect that we have not talked about that I'm curious to explore a little bit: recognition. STEPHANIE: Ooh. Yeah, that's a good one. JOËL: How important is it for you to feel recognized, either by your colleagues or by the more official org structure? STEPHANIE: This is a great question. I do value recognition from people I trust. So I think we were talking about sometimes client projects are not successful, but you tried your best, and you did do valuable work. And you might not hear that from the client. They might think differently. But if a trusted co-worker can provide that validation for you, oftentimes, I find that more helpful. JOËL: That's an interesting distinction. And I think recognition has a very different weight depending on the source it's coming from. If it's somebody you look up to, and they just give you a shout-out or something, I'm riding that high all day long. STEPHANIE: Yeah, yeah, that's a great point. How do you like to receive recognition? JOËL: Hmm. So at thoughtbot, we have an internal system where we can give shout-outs to each other. They're called high fives. And they get shared directly to the team Slack channel. And it's a small thing, but I really appreciate it when somebody calls out like, "Hey, I appreciated this thing that you did," or "This is the thing that had an impact on me," or "I appreciated the thing that you shared." Those things make me feel really great. It's a small thing. It takes 30 seconds to do. But I really appreciate that. And it's something that I am looking to more intentionally do more of because it's fun to receive recognition, but it's also really valuable to give recognition. STEPHANIE: Yeah, I'm with you. I am also trying to be intentional about being even more generous with my positive feedback for others. And I think there's also some degree of recognition and validation to give to yourself. JOËL: Self-validation. STEPHANIE: Yeah, yeah. I mean, I'm definitely trying to do more of that. Because if I'm doing work that lines up with my values, I want to be able to pat myself on the back for it, even if no one else will do it for me. [laughs] JOËL: What does that look like? You're like standing in the mirror and saying, "Good job?" STEPHANIE: [laughs] JOËL: Do you have maybe a document where you kind of list the things that you feel proud of, even if nobody else has noticed? What does that look like for you? STEPHANIE: Ooh, yeah, a brag document. I think some folks at thoughtbot have recommended doing that. For me, it's going and getting myself a treat. JOËL: Oh, I like that. STEPHANIE: So maybe like a latte the next morning or going to get just a sweet thing. Yeah, that's my way of doing it. JOËL: So we've talked about self-recognition, recognition from colleagues. I think another element is recognition from management or the company that you're working at. That can be just praise. But oftentimes, I think when you're looking at recognition from something a little more corporate, it has a more kind of concrete aspect to it. And maybe that is come yearly evaluation time; there's a raise that recognizes the fact that you've done good work. I know for me, last year, I got a big promotion. And I felt like I had been performing at a level that was kind of pretty far above and beyond the title that I had. And getting that promotion, in some ways, was very much kind of validation and recognition of the fact that I had been performing at that high level. STEPHANIE: Yeah, it sounds like the acknowledgment for the expanded work that you've been doing was really motivating for you. JOËL: Yeah. It's interesting you mentioned that acknowledgment is really motivating because it really is, and sometimes the reverse is also true. You feel discouraged or unmotivated because the good work that you're doing is not recognized. Are you familiar with the idea of intrinsic versus extrinsic motivation? STEPHANIE: Yeah, I am. Being motivated by something externally, like someone offering a promotion, or a raise, or whatever, versus it coming from yourself. JOËL: Yeah. And I think for many people, you're probably not purely motivated by one or the other. There are some things where you're motivated by your own internal values, as we mentioned earlier, and some things where you're motivated by incentives offered at work. And that balance will probably shift over time and in different moments. But having a little bit of both can be really, really powerful. If you can be living up to your values and then get rewarded for it, that's kind of peak fulfillment right there. STEPHANIE: Yeah, that's the sweet spot. Yeah, I wish that for everyone in the world. [laughs] On that note, shall we wrap up? JOËL: Let's wrap up. [laughs] STEPHANIE: Show notes for this episode can be found at bikeshed.fm. JOËL: This show has been produced and edited by Mandy Moore. STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show. JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter. STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email. JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeee!!!!!!! ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.