Podcast appearances and mentions of chris toomey

  • 16PODCASTS
  • 105EPISODES
  • 42mAVG DURATION
  • 1MONTHLY NEW EPISODE
  • Nov 25, 2024LATEST

POPULARITY

20172018201920202021202220232024


Best podcasts about chris toomey

Latest podcast episodes about chris toomey

Closing Bell
Closing Bell: Riding the Rip 11/25/24

Closing Bell

Play Episode Listen Later Nov 25, 2024 43:13


How long can this rally last as investors game-out what the new Trump administration will mean for the markets? Morgan Stanley's Chris Toomey and NewEdge's Cameron Dawson break down where they see stocks headed into the end of the year. Plus, Vista Equity Partners' Ashley MacNeill breaks down her 2025 software playbook. And, Kenny Dichter – Real SLX Founder – discusses the big business of sports betting. 

Closing Bell
Closing Bell: New Quarter for Stocks off to a Rocky Start 10/1/24

Closing Bell

Play Episode Listen Later Oct 1, 2024 41:54


Today marks a new quarter for stocks with the economy, earnings , election and geopolitics all on investors minds. Morgan Stanley's Chris Toomey – one of the country's top investment advisors – reveals how he is navigating the market right now. Plus, star chip analyst Stacy Rasgon weighs in on the sell-off in the semi space. And, we break down what to watch when Nike reports in Overtime. 

Closing Bell
Closing Bell: Bumpy Road Ahead for Stocks? 9/6/24

Closing Bell

Play Episode Listen Later Sep 6, 2024 42:11


The road ahead for stocks has gotten bumpier… but are there too many potholes to get around? Fundstrat's Tom Lee, Solus' Dan Greenhaus and Payne Capital's Courtney Garcia break down their forecasts. Plus, Morgan Stanley's Chris Toomey tells us how he is advising his clients ahead of this month's critical Fed decision. And, homebuilders were a rare bright spot in today's down tape. We tell you what's behind that big bounce. 

Closing Bell
Closing Bell: Mega Cap Moment of Truth 7/29/24

Closing Bell

Play Episode Listen Later Jul 29, 2024 42:46


Is the tech trade really in trouble… or will this week's critical earnings reports reverse the selling? Light Street Capital's Glen Kacher breaks down what he is forecasting for the sector. Plus, Morgan Stanley's Chris Toomey tells us how he is advising his high net worth clients right now. And, we drill down on the big moves in Tesla and McDonald's stocks today. 

The Bike Shed
428: Ruminating on Ruby Enumerators

The Bike Shed

Play Episode Listen Later Jun 11, 2024 35:44


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.

Closing Bell
Closing Bell: Broadening Rally Benefiting Bulls? 2/28/24

Closing Bell

Play Episode Listen Later Feb 28, 2024 43:07


Could underperforming tech actually be a good thing for this bull market? Ritholtz Wealth Management's Josh Brown and Hightower's Stephanie Link give their expert takes. Plus, Alger's Ankur Crawford says that the Mag 7 is looking more like the Mag 4 right now. She explains why and how she's navigating that trade. And, Chris Toomey from Morgan Stanley is doubling down on his bear case. He tells us why he's sticking by his stance despite the major rally. 

Closing Bell
Closing Bell: Are the Bulls Too Bullish? 01/17/24

Closing Bell

Play Episode Listen Later Jan 17, 2024 42:53


Has investor sentiment gotten too bullish? Josh Brown of Ritholtz Wealth Management, CNBC's Steve Liesman and New York Life Investment's Lauren Goodwin discuss. Plus, Morgan Stanley's Chris Toomey makes the case for caution and breaks down what he is expecting from the Fed this year. And, star VC investor Rick Heitzmann is giving his forecast for the magnificent 7. 

The Bike Shed
408: Work Device Management

The Bike Shed

Play Episode Listen Later Nov 28, 2023 32:57


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.

Giant Robots Smashing Into Other Giant Robots
500: Giant Robots Smashing Into Other Giant Robots 500th Episode!

Giant Robots Smashing Into Other Giant Robots

Play Episode Listen Later Nov 16, 2023 72:17


We released episode one of this podcast on June 11, 2012. Now, more than a decade later, we're celebrating the 500th episode of our show. In honor of this milestone, Victoria, Will, and Chad caught up with each of the past hosts of the show: Ben Orenstein, Chris Toomey, and Lindsey Christensen. We chatted about what they're up to now, what they liked and learned from hosting the show, their time at thoughtbot, and more! Follow thoughtbot on X (https://twitter.com/thoughtbot) or LinkedIn (https://www.linkedin.com/company/150727/). Become a Sponsor (https://thoughtbot.com/sponsorship) of Giant Robots! Transcript: VICTORIA: This is the Giant Robots Smashing Into Other Giant Robots Podcast, where we explore the design, development, and business of great products. I'm your host, Victoria Guido. WILL: And I'm your other host, Will Larry. CHAD: And I'm your other host, Chad Pytel. We released episode one of this podcast on June 11, 2012. Now more than a decade later, were celebrating this: the 500th episode of our show. In honor of this milestone, Victoria, Will, and I caught up with each of the past hosts of the show: Ben Orenstein, Chris Toomey, and Lindsey Christensen. We chatted about what they're up to now, what they liked and learned from hosting the show and their time at thoughtbot, and more. First up: Ben Orenstein. Ben was the very first host of the show back in 2012 when he was a developer at thoughtbot. He is now the co-founder and Head of Product at Tuple, a remote pair programming tool for designers and developers. Ben, it's great to talk to you again. It's been a while since you and I talked. How have you been? BEN: I've been decent, yeah. It's fun to be back to my roots a little bit. I told some folks that I work with that I was coming back to the pod for the 500th Episode, and they were stoked. So, it's kind of a treat to get to be on these airwaves again. CHAD: What have you been up to since you left this show and thoughtbot? BEN: Well, I started a company. So, I was at thoughtbot for a while; I think it was seven years. And I eventually sort of struck out to start my own thing–had a false start or two here and there. And then, I ended up starting a company called Tuple, and we still exist today, fortunately. Tuple is a tool for doing remote pair programming. We started off on macOS and then wrote a Linux client. And we're launching a Windows client now. But it's sort of, like, screen sharing with remote control for developers who are actually writing code and want to have great, low latency remote control and who care about screen share quality and that sort of thing. I started that about five years ago with two co-founders. Today, we are a team of 11, I think it is. And it's been going well. Our timing was really great, it turned out. We launched a little bit before COVID. So, remote work turned into a lot more of a thing, and we were already in the market. So, that helped us a ton. It was quite a wild ride there for a bit. But things have calmed down a little lately, but it's still fun. I'm, like, really enjoying being a co-founder of a software company. It was what I've always sort of wanted to do. And it turns out it actually is pretty fun and pretty great. Although there are, of course, the ups and downs of business ownership. It is never quite as calm or relaxing as being an employee somewhere else. CHAD: You started Tuple instigated by...full disclosure: thoughtbot's an early customer of Tuple. We're still a customer. We use it a lot. BEN: Woo-hoo. I appreciate that. Thank you. CHAD: If I remember right, you started and were sort of instigated to create Tuple because there was a prior product that then Slack bought, and then it started to degrade. And now, it no longer exists in the same way that it did before. BEN: Yeah. So, there was this tool called Screenhero, which I actually started using -- CHAD: [inaudible 02:14] BEN: Yeah, first at thoughtbot. Some other thoughtboter introduced me to it, and we would use it for pair programming. And I was like, oh, this is nice. And then yeah, Slack kind of acqui-hired it and more or less ended up shutting the product down. And so, there was this gap in the market. And I would ask my friends, I would ask thoughtboters and other developers, like, "What are you using now that Screenhero is gone?" And no one had a good answer. And so, after a while of this thing sort of staring me in the face, I was like, we have to try to solve this need. There's clearly a hole in the market. Yeah, so we were heavily inspired by them in the early days. Hopefully, we've charted our own path now. But they were definitely...the initial seed was, you know, let's do Screenhero but try to not get bought early or something. CHAD: [laughs] How did you or did you feel like you captured a lot of the Screenhero customers and reached them in those early days? BEN: I think so. The pitch for it was sort of shockingly easy because Screenhero had kind of blazed this trail. Like, I would often just be like, "Oh, we're making a thing. Do you remember Screenhero?" And they'd go, "Oh yeah, I loved Screenhero". I'd be like, "Yeah, we're going to try to do that." And they'd be like, "Nice. Sign me up." So, it for sure helped a ton. I have no idea what percentage of customers we converted. And they were a pretty large success, so probably a small fraction, but it definitely, like, made the initial days much easier. CHAD: Yeah. And then, like you said, COVID happened. BEN: COVID happened, yeah. I think we had been around for about a year when COVID hit. So, we were getting our feet underneath us. And we were already, like, the company was already growing at a pretty good rate, and we were feeling pretty good about it. I don't think we had quite hit ramen profitable, but we were probably pretty close or, like, flirting with it. Yeah, the business, like, I don't know, tripled or quadrupled in a matter of months. We had a few big customers that, like, just told everyone to start using Tuple. So, we had, like, thousands and thousands of new users kind of immediately. So, it was a crazy time. Everything melted, of course. We hadn't quite engineered for that much scale. We had a really rough day or so as we scrambled, but fortunately, we got things under control. And then had this, like, very nice tailwind. Because we started the company assuming that remote work would grow. We assumed that there would be more remote developers every year. And, you know, it's probably maybe 5% of dev jobs are remote or maybe even less, but we expect to see this number creeping up. We don't think that trend will reverse. And so, COVID just, like, it just yanked it, you know, a decade in the future. CHAD: You haven't tripled or quadrupled your team size, have you? BEN: No. Well, I mean, I guess, I mean, we started as 3, and now we're 11, so kind of. CHAD: [laughs] Yeah, that's true. BEN: Expenses have not grown as fast as revenue, fortunately. CHAD: That's good. That's basically what I was asking [laughs]. BEN: Yeah, yeah. We're still a pretty small team, actually. We have only, like, four or five full-time engineers on the team at the moment, which is kind of wild because we are now, you know, we have three platforms to support: Linux, Windows, and Mac. It's a pretty complicated app doing, like, real-time streaming of audio, webcams, desktops, caring about OS-level intricacies. So, I think we will be hiring more people soon, although we haven't said that for a long time. We sort of have always had a bit of a hire-slow mentality to try to get the right team members and, like, feel a real pain before we hire someone into it. But we have been getting a bit more aggressive with hiring lately. VICTORIA: Well, I really appreciate Tuple. I installed it when I first started working here at thoughtbot. And we have random pairings with everyone across the company. So, I'll randomly get to meet someone halfway across the world who's working on similar projects. And I think they really enjoy that I have a tool they like working to share what they're working on. So, I want to thank you for that. And I'm curious about when you really started to scale during COVID, what were some of the technology architecture trade-offs you came across, and where did you land with it? BEN: Well, we got fairly...I don't know if it was lucky, but we...for a long time, for years, even through COVID, maybe the first four years of the company, all Tuple calls were purely peer-to-peer. And there was no server that we owned intermediating things. This was, like, kind of one of the keys of, like, not having expenses. The scale of revenue was we could have lots more calls happen. And it wouldn't cost us bandwidth or server capacity. To this day, still, for any calls with three or fewer participants, they're purely peer-to-peer. And this is nice for latency purposes because it just...we can find the most direct path to the internet between two people. It's also nice from our cost perspective because we don't need to pay to send that data. And that was hugely useful as call volume went up immensely. Didn't have to worry too much about server load and didn't have to worry too much about bandwidth costs. CHAD: Today, is there a central service that makes the initial connection for people? BEN: Yes, yeah, yeah. So, there is a signaling server. So, when you launch the app, you sign in, and you see, like, oh, which of my co-workers are online? So, there is actually a Rails app that handles that, actually, increasingly less the Rails app. We have now...I think it's a Go service that actually manages all those. I'm further and further from the code every year. Some of the technical questions might be a little bit beyond me, or I might have slightly out-of-date info. But back to the architecture question for a second, we did a pretty big refactor when we decided to go from just being a Mac client to supporting other platforms, where we split out a cross-platform real-time communication engine written in C++ so that we could use that for all of the heavy lifting, all the managing of the connections, and the tricky bandwidth estimation, and all this stuff, and use that across different platforms. And so, today, you have the cross-platform engine, and then on top of that is a, like, a less specific layer for each of the operating systems that we support. CHAD: So, you mentioned you're less and less in the code these days. So, what do you spend your time doing then? BEN: It's a mix of things. These days, it's basically mostly -- CHAD: Just cocktails on the beach, right? BEN: Cocktails, yes [laughs], cocktails on the beach, appearing on podcasts trying to sound important and impressive, yeah. Mostly product work. So, right before this, I just got off a call with some folks from The Browser Company. They are some of our first alpha users for our new Windows clients. So, I hopped on the call with them and, like, watched three of them install the product and inevitably run into some bugs. And, you know, chatted through those with the engineer that was working on it, prioritized some stuff, made some decisions about what's coming up next, and what we're going to ignore. So, mostly product work these days. For the first five years of the company, I was CEO, so I was doing kind of everything: marketing, and also hiring, and also product. About two months ago, I stepped down as CEO, and one of my other co-founders, Spencer, stepped up. And so, now my focus has narrowed to be mostly just product stuff and much less on the marketing or hiring side. VICTORIA: Yeah, you mentioned that it was a little more comfortable to be an employee than to be a founder. I don't know if you could say more about that because, certainly, a lot of engineers are smart enough and capable enough to run their own company. But what really informed your choice there, and do you regret it? [laughs] BEN: I definitely don't regret it. thoughtbot was a close second in terms of wonderful professional experiences. But running my own thing has been the most interesting professional thing I've done by a big margin. It has also been more stressful. And, Chad, I don't know if you remember, I think, like, maybe eight years ago, you tweeted something like, if you want to sleep well at night, and, like, value that, like, peace of mind, like, don't start a company or something. I have experienced that. CHAD: [laughs] BEN: A lot more, yeah, like waking up in the middle of the night worrying about things. It feels a little bit like the highs are higher; the lows are lower. Being an employee somewhere, it's like, if this company fails, I know I can go get another job, right? Like, you're a developer. You're extremely employable. But as the owner of the company, if the company fails, like, a huge chunk of your net worth is gone. Like, this thing you poured your life into is gone. It's way more stressful and traumatic to have that happen, or have that threatened to be happening, or just imagine that happening. So, overall, I have found the trade-off to be totally worth it. It's awesome to make your own decisions and chart your own path. And when it works, it can work in a way that being a salaried employee can't. So, I'm happy with those trade-offs. But I think that is a good question for people to ask themselves as they consider doing something like this is, like: is that the kind of trade-off that you want to make? Because it has significant downsides for sure. WILL: I am a big fan of Tuple also. I love it. It [inaudible 10:08] easy, especially with remote work. You hit the jackpot with COVID and remote work, so kudos for that [laughs]. Was there anything...because I know from our previous companies, about over...hopefully a lot more of the good stuff than the bad stuff. But was there anything that you learned? Because you were at thoughtbot for seven years. Was there anything that you're like, oh my gosh, I learned that, and it's helped me till this day while I'm running my company? BEN: Yeah, quite a bit, actually. I think it'd be hard to tease apart exactly which lessons, but I do...so I ran Upcase for thoughtbot and also FormKeep. So, I got a chance to kind of run a small division of the company, while still being a normal employee and, like, having not much of that risk. And I think that was a really wonderful opportunity for me to, like, practice the skills that I was interested in. Just, like, how do you market a thing? How do you design a product and have it be good? How do you prioritize user feedback? There were a ton of lessons from those days that I feel like made me better at running our company when we actually took a shot at it. So, there were, like, the specific things that I learned by the work I was doing there. But then just, like, I mean, I think I am the programmer I am today because of, like, the weekly dev discussions that happened. Like, spending so much time with Joe Ferris and, like, trying to copy as much of his brain as possible, like, really, like, imprinted on me as, like, a programmer. And also, just, like, a lot of the sort of cultural things from my time at thoughtbot of, like, you should be sharing the things you're learning. Like, writing blog posts is a great use of time. Like, doing open-source work is a great use of time. And maybe you can't directly trace how doing, like, working in public or sharing information benefits the company. It's hard to, like, attribute it from a marketing sense. But if you sort of have faith that in the large, it's going to work out, it probably will. That feels like a thoughtbot lesson to me, and I think it has served us really well; where I recorded a weekly podcast for a long time called The Art of Product. I'm recording a new podcast called Hackers Incorporated with Adam Wathan of Tailwind fame. And I don't ever think, like, hmm, how many new leads do we think we get per episode, and how many hours has that taken? What's the ROI? I just have this sort of reflex that I developed from thoughtbot time of, like, you should be putting stuff out there, or you should be giving back. You should help other people. And that will probably help your business and make it work in the long term. CHAD: That's a good lesson [laughs]. One of the other things, you know, while you were a host of Giant Robots, you were the first host. I remember, you know, encouraging you to be the first host, and I think we talked about that in one of the episodes along the way. But we also transitioned the format a little bit, especially as you started to work on products here; you know, it was more about the building of those products and following along with those. And one of the things that sort of half-jokingly defined, I think, your impact on a lot of products was pricing, experimenting with pricing, learning about pricing, increasing prices more than people were maybe comfortable doing so. How has that worked out with Tuple, pricing in particular? BEN: It's really hard to say. It's hard to know what, like, the other path would have been through the world-. We sort of decided from, like, the early days that we wanted to have, like, a fairly premium price. Like, we wanted to be the product that was really good and was, like, a little bit annoyingly expensive, but you still paid for it because it felt worth it. And I think people could debate in both directions whether we nailed that or not. We have had a price increase that we ended up rolling back. We went, like, a little too far one time and said, "You know what? I think we're a little bit over," and we reverted that. But I would say even today, we are still a fairly pricey product. I mean, I'm pretty happy with how the company has done. I can't prove to you that, like, if the price were half what it is, we would have, you know, better success or not. CHAD: I think it'd be very hard to make the argument that if it was half that, you would have double the number of customers. BEN: Yeah, that's probably not true. CHAD: Not with the customers that you have, who are companies that will pay for products that they use as much as Tuple. BEN: Yeah, I'm happy serving the kind of companies, and they end up being mostly tech companies that really value developer happiness. When their developers come to them and they say, "We don't want to pair over Zoom. We like this thing. It's better. It feels nicer to use," they say, "Okay," and they buy the tool for them. There are places where that's not the case. And they say, "We already have a thing that does screen sharing. You're not allowed to buy this." We don't invest a lot of time trying to sell to those people or convince them that they're wrong. And I'm pretty happy serving sort of the first group. CHAD: So, you've mentioned that you've still been podcasting. To be honest, I didn't realize you were starting something new. Is it live now? BEN: It is live now, yeah. CHAD: Awesome. Where can people find that? BEN: hackersincorporated.com. It's about the transition from developer to founder, which is kind of what we've been touching on here. Yeah, hopefully, the audience is developers who want to start something or have started something who are maybe a little bit further behind progression-wise. And it's kind of, like, I have some lessons, and Adam has some lessons, and, you know, we don't think that we're experts. But sometimes it's useful to just hear, like, two people's story and sort of see, like, what seemingly has worked for them. So, we've been trying to share things there. And I think people will find it useful. VICTORIA: I was going to ask you for a lesson, maybe give us a little sample about how would you advise someone who's built a product and wants to market it, and it's targeted towards developers since you mentioned that previously as well. BEN: Yeah, in a way, the question already contains a problem. It's like, oh, I built the product; now how do I market it? It's a little bit indicative of a very common failure mode for developers, which is that. They sort of assume, okay, after you make the product, you then figure out how you're going to market it. And marketing is sort of a thing you layer on later on when you realize that just, like, throwing it on Twitter or Product Hunt didn't really work. When we started building Tuple, I was out there marketing it already. So, I had two co-founders, so this is a luxury I had. My two co-founders were writing code, and I was out doing stuff. I was recording podcasts. I was tweeting about things. I was making videos. I was giving conference talks. And I was getting people to hear about our product well before it was done. In fact, I was even selling it. I was taking pre-orders for annual subscriptions to the app while it was still vaporware. So, I would say, like, you basically can't start marketing too early. If you start marketing early and no one really cares, well, then you don't really have to build it probably. I would actually even go a little further and say, like, I started marketing Tuple before we had a product available. But in reality, I started marketing Tuple seven or so years before that when I started publishing things through thoughtbot. It's like when I was traveling around giving talks about Ruby, and when I was making screencasts about Vim, and when I was running Upcase, I was, over time, building an audience. And that audience was useful for thoughtbot, and it also was useful for me so that when I left, I had something like 10,000 Twitter followers or something, a few thousand people on our mailing list. But there were a lot of developers that already sort of knew me and trusted me to make fairly good things. And so, when I said, "Hey, I've made a new thing, and it's for you," I really benefited from those years of making useful content and trying to be useful on the internet. And in the early days, we had people sign up, and they would say, "I don't even really think I'm going to use this. But I've learned so much from you over the years that I want to support you, so I'm going to pay for a subscription." VICTORIA: I like your answer because I think the same thing when people ask me, like, because I am an organizer for Women Who Code, and I know all these great people from showing up for years in person months over months. And so, then people will ask, "Oh, how do I recruit more women in my company?" I'm like, "Well, you got to start showing up [laughs] now and do that for a couple of years, and then maybe people will trust you," right? So, I really like that answer. WILL: How has your relationship with Chad continued to grow since you left? Because seven years at the company is a lot. And it seems like you're still on really, really good terms, and you're still friends. And I know that doesn't happen at every company. BEN: I mean, it was tough deciding to leave. I think, like, both of us felt pretty sad about it. That was the longest I'd ever worked anywhere, and I really enjoyed the experience. So, I think it was tough on both sides, honestly. But we haven't kept in that much touch since then. I think we've emailed a handful of times here and there. We're both sociable people, and we sort of get each other. And there's a long history there. So, I think it's just easy for us to kind of drop back into a friendly vibe is sort of how I feel about it. CHAD: Yeah. And the way I explain it to people, you know, when you're leading a company, which Ben and I both are, you put a lot of energy into that and to the people who are on that team. If you're doing things right, there's not really hard feelings when someone leaves. But you need to put in a lot of effort to keep in touch with people outside of the company and a lot of energy. And, to be honest, I don't necessarily do as good a job with that as I would like because it's a little bit higher priority to maintain relationships with them, the people who are still at thoughtbot and who are joining. BEN: What you're saying is I'm dead to you [laughter]. That's CEO, for you're dead to me. CHAD: No. It's just...no hard feelings. BEN: Totally. CHAD: I think one of the things that has been great about the show over the years is that we haven't been afraid to change the format, which I think has been important to keeping it going. So, there is sort of; in fact, the website now is organized into seasons. And I went back and re-categorized all the episodes into seasons. And when the seasons were made up of, like, sort of the format of the show or particular hosts...when we started, it was just an interview show, and it was largely technical topics. And then we started The Bike Shed, and the technical topics sort of moved over there. But it also went with your interests more under the product and business side. Then you started working on products at thoughtbot, so it started to go even more in that. And I think Chris joined you on the show, and that was sort of all about those topics. BEN: Yeah, that makes sense. I think if you don't let the hosts kind of follow their interests, they're going to probably burn out on the thing. It's not fun to force yourself, I think, to record a podcast. CHAD: Yeah. And then when you left, you know, I took over hosting and hosted by myself for a while, went back to the interview format, but then was joined by Lindsey for a little while. We experimented with a few different things: one, interviews, but then we did a whole, just under a year, where we followed along with three companies. And each month, we would have an interview episode where we talked to them, all three companies, about the same topic. And then, we also did an episode with just Lindsey and I talking about that topic and about what we learned from the startup companies that we were following along with for the year. And now we're back to interview freeform, different guests, different topics. It seems like we're going to stick with that for a little while. But, obviously, as Will and Victoria have said, like, we'll probably change it again in some way, you know, a year, two years, three years from now. VICTORIA: Yeah, and I'm definitely bringing my interest around DevOps and platform engineering, so you'll see more guests who have that focus in their background. And with that, sometimes my interview style is more; how do I ask a question that I can't read from your developer docs and that I might not understand the answer to? [laughs] That's kind of where I like to go with it. So yeah, I'm really excited about...it's probably one of my favorite parts of my job here at thoughtbot because I get to meet so many interesting people. And, hopefully, that's interesting to everyone else [laughs] and our guests, yeah. BEN: Totally. Well, I dramatically underestimated how awesome it would be to meet all kinds of cool people in the industry when I started the podcast. I didn't truly connect in my head, like, wait a second, if I have a 45-minute conversation with, like, a lot of prominent, awesome people in our field, that's going to be really interesting and useful for me. So, I think, yeah, it's nice to be in the hosting seat. VICTORIA: And it's so surprising how I'll meet someone at a conference, and I'll invite them onto the podcast. And the way it winds up is that whatever we're talking about on the show is directly relevant to what I'm working on or a problem that I have. It's been incredible. And I really appreciate you for coming back for our 500th Episode here. CHAD: Ben, thanks very much again for joining us, and congratulations on all the success with Tuple. And I wish you the best. BEN: Thank you so much. Thanks for being a continuing customer. I really appreciate it. CHAD: Next, we caught up with Chris Toomey, who had a run as co-host of the show with Ben throughout 2016. CHRIS: Hi there. Thanks for having me. So, we're talking with all of the past hosts. I know you joined the show, and you were on it with Ben. And then you moved over to The Bike Shed, right? CHRIS: Yeah. So, I had co-hosted with Ben for about six months. And then I think I was transitioning off of Upcase, and so that ended sort of the Giant Robots “let's talk about business” podcast tour for me. And then, I went back to consulting for a while. And, at some point, after Derek Prior had left, I took over as the host of The Bike Shed. So, I think there was probably, like, a year and a half, two-year gap in between the various hostings. CHAD: Are you doing any podcasting now? CHRIS: I'm not, and I miss it. It was a lot of fun. It was, I think, an ideal medium for me. I'm not as good at writing. I tend to over-edit and overthink. But when you get me on a podcast, I just start to say what's in my head, and I tend to not hate it after the fact. So [chuckles], that combination I found to be somewhat perfect for me. But yeah, lacking that in my current day-to-day. CHAD: Well, what's been taking up your time since you left? CHRIS: I had decided it was time to sort of go exploring, try and maybe join a startup, that sort of thing. I was sort of called in that direction. So, just after I left thoughtbot, I did a little bit of freelancing, but that was mostly to sort of keep the lights on and start to connect with folks and see if there might be an opportunity out there. I was able to connect with a former thoughtbot client, Sam Zimmerman, who was looking to start something as well. And so, we put our act together and formed a company called Sagewell, which was trying to build a digital financial platform for seniors, which is a whole bunch of different complicated things to try and string together. So, that was a wonderful experience. I was CTO of that organization. And I think that ran for about two and a half years. Unfortunately, Sagewell couldn't quite find the right sort of sticking point and, unfortunately, shut down a little bit earlier in this year. But that was, I would say, the lion's share of what I have done since leaving thoughtbot, really wonderful experience, got to learn a ton about all of the different aspects of building a startup. And I think somewhat pointedly learned that, like, it's messy, but I think I do like this startup world. So, since leaving Sagewell, I've now joined a company called August Health, which has a couple of ex-thoughtboters there as well. And August is post their Series A. They're a little bit further along in their journey. So, it was sort of a nice continuation of the startup experience, getting to see a company a little bit further on but still with lots of the good type of problems, lots of code to write, lots of product to build. So, excited to be joining them. And yeah, that's mostly what's taking up my time these days. CHAD: So, I know at Sagewell, you made a lot of technical architecture, team decisions. It was Rails in the backend, Svelte in the frontend, if I'm not mistaken. CHRIS: Yep, that's correct. CHAD: You know, hindsight is always 2020. Is there anything you learned along the way, or given how things ended up, that you would do differently? CHRIS: Sure. I was really happy with the tech stack that we were able to put together. Svelte was probably the most out there of the choices, I would say, but even that, it was sort of relegated to the frontend. And so, it was a little bit novel for folks coming into the codebase. Most folks had worked in React before but didn't know Svelte. They were able to pick it up pretty quickly. But Inertia.js was actually the core sort of architecture of the app, sort of connected the frontend and the backend, and really allowed us to move incredibly quickly. And I was very, very happy with that decision. We even ended up building our mobile applications, both for iOS and Android. So, we had native apps in both of the stores, but the apps were basically wrappers around the Rails application with a technology similar to Turbolinks native–if folks are familiar with that so, sort of a WebView layer but with some native interactions where you want. And so, like, we introduced a native login screen on both platforms so that we could do biometric login and that sort of thing. But at the end of the day, most of the screens in the app didn't need to be differentiated between a truly native mobile app and what like, mobile WebView would look like. So, we leaned into that. And it was incredible just how much we were able to do with that stack and how quickly we were able to move, and also how confidently we were able to move, which was really a nice thing. Having the deep integration between the backend and the frontend really allowed a very small team to get a lot done in a short time. CHAD: Does that code live on in any capacity? CHRIS: No. CHAD: Oh. How does that make you feel? [chuckles] CHRIS: It makes me feel very sad, I will say. That said, I mean, at the end of the day, code is in service of a business. And so, like, the code...there are, I think, probably a couple of things that we might be able to extract and share. There were some interesting...we did some weird stuff with the serializers and some, like, TypeScript type generation on the frontend that was somewhat novel. But at the end of the day, you know, code is in service of a business, and, unfortunately, the business is not continuing on. So, the code in the abstract is...it's more, you know, the journey that we had along the way and the friends we made and whatnot. But I think, for me, sort of the learnings of I really appreciate this architecture and will absolutely bring it to any new projects that I'm building from, you know, greenfield moving forward. VICTORIA: I'm curious what it was like to go from being a consultant to being a big player in a startup and being responsible for the business and the technology. How did that feel for you? CHRIS: I would say somewhat natural. I think the consulting experience really lent well to trying to think about not just the technical ramifications but, you know, what's the business impact? How do we structure a backlog and communicate about what features we want to build in what order? How do we, you know, scope a minimal MVP? All those sorts of things were, I think, really useful in allowing me to sort of help shape the direction of the company and be as productive of an engineering team as we could be. CHAD: A lot of the projects you worked on at thoughtbot were if not for startups, helping to launch new products. And then, a lot of the work you did at thoughtbot, too, was on Upcase, which was very much building a business. CHRIS: Yes. I definitely find myself drawn in that direction, and part of like, as I mentioned, I seem to be inclined towards this startup world. And I think it's that, like, the intersection between tech and business is sort of my sweet spot. I work with a lot of developers who are really interested in getting sort of deeper into the technical layers, or Docker and Kubernetes and orchestration. And I always find myself a little bit resistant to those. I'm like, I mean, whatever. Let's just...let's get something out there so that we can get users on it. And I am so drawn to that side, you know, you need both types of developers critically. I definitely find myself drawn to that business side a little bit more than many of the folks that I work with, and helping to bridge that gap and communicate about requirements and all those sort of things. So, definitely, the experience as a consultant really informed that and helped me have sort of a vocabulary and a comfort in those sort of conversations. WILL: How did Upcase come about? Because I know I've talked to numerous people who have gone through Upcase. I actually went through it, and I learned a ton. So, how did that come about? CHRIS: I think that was a dream in Ben Orenstein's eye. It started as thoughtbot Learn many, many years ago. There was a handful of workshops that had been recorded. And so, there were the video recordings of those workshops that thoughtbot used to provide in person. Ben collected those together and made them sort of an offering on the internet. I think Chad, you, and I were on some podcast episode where you sort of talked about the pricing models over time and how that went from, like, a high dollar one-time download to, like, $99 a month to $29 a month, and now Upcase is free. And so, it sort of went on this long journey. But it was an interesting exploration of building a content business of sort of really leaning into the thoughtbot ideal of sharing as much information as possible, and took a couple of different shapes over time. There was the weekly iterations of the video series that would come out each week, as well as the, like, longer format trails, and eventually some exercises and whatnot, but very much an organic sort of evolving thing that started as just a handful of videos and then became much more of a complete platform. I think I hit the high points there. But, Chad, does that all sound accurate to you? CHAD: Yeah, I led the transition from our workshops to Learn, which brought everything together. And then, I stepped away as product manager, and Ben took it the next step to Upcase and really productized it into a SaaS sort of monthly recurring billing model and took it over from there. But it still exists, and a lot of the stuff there is still really good [laughs]. CHRIS: Yeah, I remain deeply proud of lots of the videos on that platform. And I'm very glad that they are still out there, and I can point folks at them. VICTORIA: I love that idea that you said about trying to get as much content out there as possible or, like, really overcommunicate. I'm curious if that's also stayed with you as you've moved on to startups, about just trying to get that influence over, like, what you're doing and how you're promoting your work continues. CHRIS: I will say one of the experiences that really sticks with me is I had followed thoughtbot for a while before I actually joined. So, I was reading the blog, and I was listening to the podcasts and was really informing a lot of how I thought about building software. And I was so excited when I joined thoughtbot to, like, finally see behind the curtain and see, like, okay, so, what are the insider secrets? And I was equal parts let down...actually, not equal parts. I was a little bit let down but then also sort of invigorated to see, like, no, no, it's all out there. It's like, the blog and the open-source repos and those sort of...that really is the documentation of how thoughtbot thinks about and builds software. So, that was really foundational for me. But at the same time, I also saw sort of the complexity of it and how much effort goes into it, you know, investment time Fridays, and those sort of things. Like, a thoughtbot blog post is not a trivial thing to put up into the world. So many different people were collaborating and working on it. And so, I've simultaneously loved the sharing, and where sharing makes sense, I've tried to do that. But I also recognize the deep cost. And I think for thoughtbot, it's always made sense because it's been such a great mechanism for getting the thoughtbot name out there and for getting clients and for hiring developers. At startups, it becomes a really interesting trade-off of, should we be allocating time to building up sort of a brand in the name and getting ourselves, you know, getting information out there? Versus, should we be just focusing on the work at hand? And most organizations that I've worked with have bias towards certainly less sharing than thoughtbot, but just not much at all. Often, I'll see folks like, "Hey, maybe we should start a blog." And I'm like, "Okay, let's just talk about how much effort that [laughs] actually looks like." And I wonder if I'm actually overcorrected on that, having seen, you know, the high bar that thoughtbot set. CHAD: I think it's a struggle. This is one of my [laughs] hot topics or spiels that I can go on. You know, in most other companies, that kind of thing only helps...it only helps in hiring or the people being fulfilled in the work. But at most companies, your product is not about that; that's not what your business is. So, having a more fulfilled engineering team who is easier to hire—don't get me wrong, there are advantages to that—but it doesn't also help with your sales. CHRIS: Yes. CHAD: And at thoughtbot, our business is totally aligned with the people and what we do as designers and developers. And so, when we improve one, we improve the other, and that's why we can make it work. That is marketing for the product that we actually sell, and that's not the case at a SaaS software company. CHRIS: Yes, yeah, definitely. That resonates strongly. I will say, though, on the hiring side, hiring at thoughtbot was always...there was...I won't say a cheat code, but just if someone were to come into the hiring process and they're like, "Oh yeah, I've read the blog. I listen to the podcast," this and that, immediately, you were able to skip so much further into the conversation and be like, "Okay, what do you agree with? What do you disagree with? Like, let's talk." But there's so much. Because thoughtbot put so much out there, it was easy to say, like, "Hey, this is who we are. Do you like that? Is that your vibe?" Whereas most engineering organizations don't have that. And so, you have to try and, like, build that in the context of, you know, a couple of hour conversations in an interview, and it's just so much harder to do. So, again, I've leaned in the direction of not going anywhere near thoughtbot's level of sharing. But the downside when you are hiring, you're like, oh, this is going to be trickier. CHAD: Yeah. One of the moments that stands out in my mind, and maybe I've told this story before on the podcast, but I'll tell it again. When we opened the New York studio, it was really fast growing and was doing a lot of hiring. And one of the people who had just joined the company a couple of weeks before was doing an interview and rejected the person was able to write an articulate reason why. But it all boiled down to this person is, you know, not a fit for thoughtbot. Based on what they were able to describe, I felt very confident with the ability or with the fact that they were able to make that call, even though they had been here only a couple of weeks, because they joined knowing who we were, and what we stand for, and what our culture and our values are, and the way that we do things, and all that kind of thing. And so, yeah, that's definitely a huge benefit to us. VICTORIA: I've certainly enjoyed that as well, as someone who hires developers here and also in meeting new companies and organizations when they already know thoughtbot. That's really nice to have that reputation there, coming from my background—some really more scrappier startup kind of consulting agencies. But, you know, I wanted to talk a little bit more about your podcasting experience while you're here. So, I know you were on both The Bike Shed and Giant Robots. Which is the better podcast? [laughter] So, what's your...do you have, like, a favorite episode or favorite moment, or maybe, like, a little anecdote you can share from hosting? CHRIS: Well, I guess there's, like, three different eras for me in the podcasting. So, there's Giant Robots with Ben talking more about business stuff, and I think that was really useful. I think it was more of a forcing function on me because I sort of...Both Ben and I were coming on; we were giving honest, transparent summaries of our, like, MRR and stats and how things were growing, and acted as sort of an accountability backstop, which was super useful but also just kind of nerve-wracking. Then, when I joined the Bike Shed, the interviewing sequence that I did each week was just a new person that I was chatting with. And I sort of had to ramp them up on, hey, here's a quick summary on how to think about podcasting. Don't worry, it'll be great. Everybody have fun. But I was finding each of the guests. I was sort of finding a topic to talk about with them. So, that ended up being a lot more work. And then, the last three years chatting with Steph that was by far my favorite. There was just such a natural back-and-forth. It really was just capturing the conversations of two developers at thoughtbot and the questions we would ask each other as we hit something complicated in a piece of code or, "Oh, I saw this, you know, article about a new open-source repository. What do you think about that?" It was so much easier, so much more natural, and, frankly, a lot of fun to do that. And, two, I actually do have an answer to the favorite podcast episode, which is the first episode that Steph was ever on. It was before she actually joined as a co-host. But it was called “What I Believe About Software.” And it was just this really great, deep conversation about how we think about software. And a lot of it is very much, like, thoughtbot ideals, I would say. But yeah, Steph came in and just brought the heat in that first episode, and I remember just how enjoyable that experience was. And I was like, all right, let's see if I can get her to hang out a little bit more, and, thankfully, she was happy to join. WILL: What was your favorite position, I guess you can call it? Because you say you like the mixture of business and, you know, development. So, you've been in leadership as development director, CTO. You've been a web developer. You've been over content, like, with Upcase. What was your favorite position [inaudible 16:43] you were doing, and why was it your favorite? CHRIS: The development director role feels like sort of a cheating answer, but I think that would be my answer because it contained a handful of things within it. Like, as development director, I was still working on client projects three days a week. And then, one day a week was sort of allocated to the manager-type tasks, or having one-on-ones with my team sort of helping to think about strategy and whatnot. And then, ideally, still getting some amount of investment time, although the relative amounts of those always flexed a little bit. Because that one sort of encompassed different facets, I think that's going to be my answer. And I think, like, some of what drew me to consulting in the first place and kept me in that line of work for seven years was the variety, you know, different clients, as well as, even within thoughtbot, different modes of working in podcasts or video. Or there was a bootcamp that I taught, a session of Metis, which that was a whole other experience. And so, getting that variety was really interesting. And I think as sort of a tricky answer to your question, the development director role as a singular thing contained a multitude, and so I think that was the one that would stand out to me. It's also the most, you know, the one that I ended on, so [laughs] it might just be recency bias, but yeah. VICTORIA: Oh, I love that. Is there anything else that you would like to promote on the podcast today? CHRIS: No, although as you ask the question, I feel like I should, I don't know, make some things to promote, get back into some, I don't know, content generation or something like that. But for now, no. I'm, you know, diving into the startup life, and it's a wonderful and engrossing way to do work, but it does definitely take up a lot of my headspace. So, it's an interesting trade-off. But right now, I don't know; if folks are online and they want to say hi, most of my contact information is readily available. So, I would love to say hi to folks, anyone that listened in the past or, you know, has any thoughts in the now. Would love to connect with folks. But otherwise, yeah, thank you so much for having me on. CHAD: In 2017, I took over from Ben as solo host of the show but was joined by Lindsey Christainson as cohost in 2019. After some time away from thoughtbot, Lindsey is back with us and we sat down to catch up with her. VICTORIA: Why don't you tell me about your current role with thoughtbot? LINDSEY: I am currently supporting marketing and business development at thoughtbot, as well as working as a marketing consultant for thoughtbot clients. VICTORIA: Great. And I understand that you had worked with thoughtbot many years ago, and that's when you also came on as a co-host of Giant Robots. Is that right? LINDSEY: Yeah, a couple of years ago. I left thoughtbot in spring of 2021. And I forget how long my stint was as a co-host of Giant Robots, but over a year, maybe a year and a half, two years? CHAD: Yeah, I think that's right. I think you started in 2019. LINDSEY: Yeah. Yeah, that sounds right. And Chad and I were co-hosts, I think, similar to the setup today in which sometimes we hosted together, and sometimes we were conducting interviews separately. CHAD: And then we sort of introduced a second season, where we followed along with a batch of companies over the course of the entire season. And that was fun, and we learned a lot. And it was nice to have consistent guests. LINDSEY: Yeah, that was a lot of fun. I really liked that format. I don't know; they almost were, like, more than guests at that point. They were just like other co-hosts [laughs] that we could rely on week in, week out to check in with them as they're working on early-stage companies. So, every time we checked in with them, they usually had some new, exciting developments. WILL: I really like that idea. How did y'all come up with that? CHAD: I'm not sure. I think a few years before I had taken over hosting of the show, and I forget...my memory maybe is that I went to Lindsey and said, "You know, let's do something different." But I'm not sure. Does that match your memory, Lindsey? LINDSEY: Yeah, I think there were two main drivers; one was I think you were feeling like you were having similar conversations in the interviews every time. Like, you couldn't get to a certain depth because every time you were interviewing someone, you were doing, like, the, "Well, tell me your founding story." And, you know, how did you raise funding? It kind of got a little bit repetitive. And then, on the side, the few we had done together, I think we both really enjoyed. So, we were thinking, like, what's the format in which the two of us could co-host together more regularly? Because I'm a pleasure to talk to [laughter]. I think you were like, I need to talk to Lindsey more. [inaudible 3:13] VICTORIA: What is your hosting style? How would you describe your approach to hosting a podcast? LINDSEY: I mean, obviously, it's a podcast about products and business. I think as a marketer, I am, you know, drawn a lot to the marketing side, so tending to ask questions around go-to-market audience, users. That's always just, like, a particular interest of mine. But then also, like, the feelings. I love asking about the feelings of things, you know, how did it feel when you started? How did it feel when you made this tough decision? So, that's another thing I think I noticed in my interviews is asking about some of the emotions behind business decisions. VICTORIA: And I like hearing about how people felt at the time and then how they felt afterwards [laughs]. And, like, how people around them supported each other and that type of thing. That's really fun. I'm curious, too, from your marketing background and having to do with podcasts like; some founders, I think, get the advice to just start a podcast to start building a community. But I'm curious on your thoughts about, like, how does podcasting really play into, like, business and marketing development for products? LINDSEY: Oh yeah. It's become definitely, like, a standard channel in B2B these days. I feel like that it's pretty typical for a company to have a podcast as one way that they engage their audience and their users. In marketing, you're really vying for people's attention, and people's attention span is getting shorter and shorter. So, like, if you have an ad or a blog, you're getting, like, seconds, maybe minutes of someone's attention. And whereas something like a podcast offers a unique channel to have someone's undivided attention for, you know, 30 minutes, an hour, and if you're lucky, you know, checking back in week over week. So, it became a really popular method. That said, I think you're probably also seeing the market get saturated [laughs] with podcasts now, so some diminishing returns. And, you know, as always, kind of looking for, you know, what's the next way? What's the next thing that people are interested in in ways to capture their attention? CHAD: What is the next thing? LINDSEY: I don't know, back to micro-content? TikTok videos -- CHAD: Yeah, I was going to say TikTok, yeah. LINDSEY: Yeah, you know, 10-30 seconds, what can you communicate? VICTORIA: I see people live streaming on Twitch a lot for coding and developer products. LINDSEY: Yeah, I think we've seen some of that, too. We've been experimenting more at thoughtbot with live streaming as well. It's another interesting mechanism. But yeah, I don't know, it's interesting. It's another form of, like, community and how people engage with their communities. So, it's always evolving. It's always evolving, and sometimes it's not. Sometimes, people just do want to get in a room together, too, which is always interesting. WILL: What has been, in your experience, the good the bad? Like, how do you feel about the way that it has shifted? Because I think you started in, like, 2000, like, kind of earlier 2000, 2005, something around there. And it was totally different than now like you're saying. Because I feel like, you know, Channel 5 30-second ad, you know, with some of the marketing depending on what you're doing, to now to where you're, like, you're paying influencers to advertise your product, or you're doing an ad. Or it's more social media-driven and tech-driven. What has been your opinion and feelings on the way that it has grown and evolved? LINDSEY: Marketing, in general, yeah, I graduated college in 2005 and started my marketing career. And yeah, you could, like, actually get people to click on banner ads back then, which was pretty [inaudible 07:14] [laughs]. WILL: I forgot about banner ads [laughs]. LINDSEY: I don't know, yeah. I don't know. In order for myself to not just get too frustrated, I think I've got to, like, view it as a game kind of. What new things are we going to try? You know, what do we see work? But it can really depend. And I've always been in B2B side of things. And consumer, I'm sure, has its own kind of evolution around how people engage and how they consume content and byproducts. But in B2B, you know, it can really depend on industry too. You know, I'm working with a client right now in the senior living space, and they're really big in in-person conferences. So, that's how people consume, get a lot of their information and, make connections, and learn about new products. So, it's been interesting to work in an industry that what might be considered, like, a little bit more old-school channels are still effective. And then just thinking about how you weave in the new channels with the existing ones without ignoring them. They might get information in conferences, but they're still a modern human who will then, you know, search online to learn more, for example. VICTORIA: It reminds me of a phrase I like to say, which is that, like, technology never dies; you just have more of it. There's just more different options and more different ways to do things. And some people are always, you know, sometimes you have to be flexible and do everything. CHAD: So, tell us more about what you did in between...after you left thoughtbot, what did you do? LINDSEY: I was heading up B2B marketing for a company called Flywire, which is headquartered in Boston but is a global company now. And they were just kind of starting their B2B business unit, which, as I mentioned, B2B is my personal specialty. I had been connected to their CMO through the Boston startup community. And yeah, I was helping them kind of launch their go-to-market for B2B. The industries they were in before...they got their start in higher education and then expanded in healthcare and found a niche in luxury travel, and then we were figuring out the B2B piece. But yeah, I was there for about a year and a half. They actually went public the second week I was there, which was an interesting [laughs] experience. I knew they were, like, on that journey, but it was kind of funny to be there the second week, and people were, like, "Congrats." And I was like, "Well, I definitely didn't have anything to do with it because I just finished my onboarding, but thank you," [laughs]. CHAD: One of the things that really impressed me when you joined thoughtbot was the way in which you learned about who we were and really internalized that in a way where you were then able to pretty meaningfully understand our market, our positioning in the market, and come up with new strategies for us. I assume that's something you're good at in general [laughs]. How do you approach it? How did you approach it when you joined Flywire, for example? And how was it the same or different than how you approached thoughtbot? LINDSEY: Ooh, yeah, that's a good question. And I appreciate that comment because it's difficult. But I think, yeah, with any new organization that I'm joining, you know, I think starting out with your kind of mini-listening tour of your key stakeholders across, you know, the different departmental focuses to get a sense of, what are the challenges? What are the opportunities? It's actually like, you know, it's the SWOT analysis, kind of trying to fill in your own mind map of a SWOT analysis of where the company is. What are the major hurdles you're facing? Where are people trying to go? What have they tried that's worked? What have they tried that's failed? But then, like, I think for the culture component, I think a part of that maybe is, like, feel, and maybe something that I do have a knack for. Again, maybe this is, like, you know, emotional intelligence quotient, where it's like, you know, but it's the company, you know, who is this company? What is important to them? How do they work and go about things? I know thoughtbot is certainly very unique, I think, in that arena in terms of being, like, a really value-driven company, and one where especially, like, marketing and business work is, like, distributed across teams in a really interesting way. You know, I'm sure the fact that it fascinated me and was something I could get passionate and get behind was something that also helped me understand it quickly. CHAD: I was excited that...or it was sort of a coincidence because I had reached out to you and without realizing that you had left Flywire. And Kelly, who had been doing a combined sales and marketing role, was going on parental leave. And so, it was fortuitous [laughs] that you were able to come back and help us and provide coverage, like, Kelly was out. LINDSEY: Yeah, it definitely felt like stars aligned moment, which, you know, I'm pretty woo-woo, so I believe in [laughter]...I believe in that kind of thing. You know, yeah, it was wild. It really did feel like your email came out of nowhere. And, you know, I mentioned it, obviously, to my partner and my friends. And they were like, "Oh, he definitely knows, like, that you left your last company." And I'm like, "I actually don't think he does [laughter]. I actually don't think he does." Yeah, and then we started chatting about me coming back to help. And it was great. thoughtbot makes it hard to work anywhere else [laughs]. So, I was happy to come back. I missed the team. CHAD: And one of the exciting things, and you've mentioned it, is you're not just doing marketing for thoughtbot now. We have started to offer your services to our clients. LINDSEY: Yeah, I'm super excited about this. And it's something I'd started thinking about. I had decided to take some time off between Flywire and my next thing and had started thinking about doing marketing, consulting. And as I'm doing that, I'm thinking a lot about how thoughtbot does consulting and, you know, wanting to emulate something like that. So, I started back up at thoughtbot. That wasn't part of the plan. I was just going to, you know, fill in for Kelly and help with marketing things. But then, you know, a good opportunity arose to work on a client, and I was really excited. When, you know, Chad, you and I chatted through it, we came to the conclusion that this was something worth exploring under the, you know, thoughtbot umbrella. And it's been a really great experience so far. And we now have brought on another client now. And if you're listening and need early-stage B2B marketing support, reach out to lindsey@thoughtbot.com. CHAD: Definitely. And Lindsey is pretty good, so you're going to like it [laughs]. LINDSEY: Yeah, you're going to like the way you look. WILL: Yeah, definitely. Because I can even feel your presence here, you know, coming back. Because even like, you know, the market where it's at now and some of the suggestions that, you know, you've been helping us. For example, like, I do a lot of React Native, and you're like, "Hey, you know, blog posts have done a lot of traction, you know, let's get some more blog posts out in the market to help with the traffic and everything." So, the question I have with that is, like, thank you for even suggesting that because it's, like, those little things that you don't even think about. It's like, oh yeah, blog posts, that's an easy transition to help the market, clients, things like that. But with the market the way it is, what has been your experience working during this time with the market? I don't know if you want to call it struggling, but whatever you want to call it that, it's doing [laughs]. LINDSEY: Yeah, I mean, the economy is difficult now. We also went through a really tough spot when I was here last time. During COVID, you know, we faced a major company challenge. And, I mean, I'll let Chad speak to it, but I would imagine it's probably one of the bigger, like, economic inflection points that you faced. Would you say that? CHAD: Yeah, definitely. The thing about it that made it worse was how quickly it happened. You know, it was something that you didn't see coming, and then, you know, about 40% of our business went away in a single month. That's the kind of thing that was a real shock to the system. I think the thing that made it difficult, too, was then the aspects of COVID, where we were no longer able to go into our studios. We were all working remotely. We were isolated from each other. And so, that made executing on what needed to be done in order to make the company survive additionally challenging. LINDSEY: Yeah, so I think, like, going through that experience, also, and seeing how the team and the leadership team rallied together to get through it. And then, you know, ultimately, I think 2021 and 2022 have, like, really good years. That was a really positive experience. And something I'll definitely take with me for a while is just, like, keeping a cool head and just knowing you have, like, really smart, talented folks with you working on it and that you can get through it. And just, like, doing some, I mean, we relied on what we did best, which was, like, design thinking, using design exercise to think about, like, how we might re-organize the company, or what other services we might try launching, or how might we re-package, you know, larger services into smaller more palatable services when people have, like, kind of tighter purse strings. So, that was, like, a great educational experience, and I think something we just continue to do now: be open to change, be open to changing how we package services, what clients we go after, and coming at it with, like, an agile, experimental mindset and try to find out what works. VICTORIA: I really appreciate that. And it aligns now with the new service we've developed around you and the marketing that you provide. And I'm curious because I've had founders come up to me who say they need help with marketing or they need to, like, figure out their marketing plans. So, say you've met a founder who has this question, like, what questions do you ask them to kind of narrow down what it is they really need and really want to get out of a marketing plan? LINDSEY: I've been thinking about this a lot recently. And, like, obviously, I see other marketing leaders in the market. Marketers like to talk about what they do on LinkedIn [laughs], so I get to...I read a lot about different people's approaches to this. And some people kind of go in and are like, okay, this is what you need. This is how we're going to do it, and they start executing on it. And I really do take a very collaborative approach with founders. I think they're, especially in early stage, they're your most important asset in a way, and a lot of their intuition around the market and the business, you know, it's gotten them to where they're at. And so, I think starting from the point of, like, taking what they view as priorities or challenges, and then helping them better explore them or understand them with my own marketing experience and expertise, to

Closing Bell
Closing Bell: All-Clear for Stocks? 11/3/23

Closing Bell

Play Episode Listen Later Nov 3, 2023 42:50


This week we got a jobs report, Apple earnings and a Fed meeting… and stocks rallied after each one of them. Is this the all-clear for stocks investors have been waiting for? New York Life Investments' Lauren Goodwin gives her take. Plus, Apple shareholder Bryn Talkington of Requisite Capital Management reacts to the company's sales numbers. And, Morgan Stanley's Chris Toomey explains how he is advising his high net worth clients right now.

East Meets West Hunt
Ep. 319: Finding the Ultimate Truck Camping Setup for Hunting Trips with Chris Toomey and Kurt Martonik

East Meets West Hunt

Play Episode Listen Later Sep 26, 2023 107:32


Beau Martonik is joined by Chris Toomey and Kurt Martonik. The three of them have traveled to hunt in many different states, using their vehicles as basecamps. With three different truck camping setups, they discuss what has worked for them, what hasn't, what they would change, and the specific gear used for making truck camping work for hunting trips. Topics: 00:00:00 - Start 00:12:32 - Beau and Chris meeting through Johnny Stewart 00:16:51 - Truck camping talk begins 00:20:33 - Four Wheel campers 00:22:50 - Kurts Toyota 4runner setup 00:27:02 - Beau's evolution of his setup 00:33:18 - Camp in, Camp on, Camp out 00:41:39 - Things you are bringing, how you are organizing it 00:49:53 - Camping food 00:56:16 - More on Chris' setup 01:02:31 - Scent control 01:04:58 - Non-dispersed camping 01:06:13 - Other tools - generators, power sources, and working remotely 01:11:31 - Gas and fuel 01:14:01 - Water 01:17:57 - Showering 01:22:11 - Saving money on hotel rooms? 01:24:16 - Building your setup is a slow progression 01:33:36 - Make sure you are burning the right wood in your stove Note** timestamps might be off by roughly 4 minutes on the audio version due to ad length changes. Resources: GoWild: Beau Martonik (East Meets West Hunt) Instagram:   @eastmeetswesthunt @beau.martonik @kurt_the_gunsmith @christoomeyofficial Facebook:   East Meets West Outdoors   Website/Apparel/Deals: https://www.eastmeetswesthunt.com/ YouTube: Beau Martonik - https://www.youtube.com/channel/UCQJon93sYfu9HUMKpCMps3w Partner Discounts and Affiliate Links: https://www.eastmeetswesthunt.com/partners Amazon Influencer Page https://www.amazon.com/shop/beau.martonik Learn more about your ad choices. Visit megaphone.fm/adchoices

The Bike Shed
403: Productivity Tricks

The Bike Shed

Play Episode Listen Later Sep 26, 2023 37:49


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.

Closing Bell
Closing Bell: Musk's Moment of Truth 5/12/23

Closing Bell

Play Episode Listen Later May 12, 2023 42:51


Elon Musk stepping aside as CEO of Twitter – presumably to spend more time on everything else he has going on… including Tesla. That stock is now looking for momentum. EMJ's Eric Jackson gives his forecast.  Plus, Morgan Stanley's Chris Toomey says one sector is “priced to perfection.” He explains which one and why. And, Jessica Inskip of Options Play highlights the key technical levels investors should be watching.

The Bike Shed
380: Remote Work Life

The Bike Shed

Play Episode Listen Later Apr 18, 2023 32:19


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.

Closing Bell
Closing Bell: Sell Before May and Go Away? 4/13/23

Closing Bell

Play Episode Listen Later Apr 13, 2023 42:29


Wells Fargo's Chris Harvey urged investors to “sell before May and go away” … calling for a meaningful correction in stocks. He explains his point of view. Lauren Goodwin of New York Life Investment and Joe Terranova of Virtus Investment Partners give their forecasts. Plus, Morgan Stanley's Chris Toomey says we're facing a “fairly dramatic” sell-off. And, the key themes every investor needs to be watching when United Health reports tomorrow morning.

Closing Bell
Closing Bell: Rescuing First Republic, What Will The Fed Do Next? 3/16/23

Closing Bell

Play Episode Listen Later Mar 16, 2023 43:08


Scott Wapner breaks down the big break for First Republic.  Eleven banks, including JPMorgan, Citigroup, Bank of America and Wells Fargo, deposite $30 billion in First Republic Bank. In a joint statement from the heads of the Treasury, Federal Reserve, FDIC and the office of the Comptroller of the Currency writing, “This show of support by a group of large banks is most welcome, and demonstrates the resilience of the banking system.”  SoFi's Head of Investment Strategy, Liz Young, weighing in on what it all means for the markets and your money.  Plus, one of the top-rated financial advisors, Chris Toomey, on how he's positioning his clients through the volatility.  Why he's saying now is the time to stay defensive. The tech trade heating up, Requisite Capital's Bryn Talkington on where she's putting her money to work.

The Bike Shed
369: Most Impactful Articles of 2022

The Bike Shed

Play Episode Listen Later Jan 31, 2023 50:00


Joël has been pondering another tool for thought from Maggie Appleton: diagramming. What does drawing complex things reveal? Stephanie has updates on how Soup Group went, plus a clarification from last week's episode re: hexagons and tessellation. They also share the top most impactful articles they read in 2022. 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. Maggie Appleton tools for thought (https://maggieappleton.com/tools-for-thought) Squint test (https://www.youtube.com/watch?v=8bZh5LMaSmE&themeRefresh=1) Cardinality of types (https://guide.elm-lang.org/appendix/types_as_sets.html) Honeycomb hexagon construction (https://www.nature.com/articles/srep28341) Coachability (https://cate.blog/2021/02/22/coachability/) Strangler Fig Pattern (https://shopify.engineering/refactoring-legacy-code-strangler-fig-pattern) Finding time to refactor (https://thoughtbot.com/blog/finding-the-time-to-refactor) Parse don't validate (https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/) Errors cluster around boundaries (https://thoughtbot.com/blog/debugging-at-the-boundaries) Transcript: STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot that has basically become a two-person book club between me and Joël. [laughter] JOËL: I love that. STEPHANIE: I'm so sorry, I had to. I think we've been sharing so many things we've been reading in the past couple of episodes, and I've been loving it. I think it's a lot of the conversations we have off-air too, and now we're just bringing it on on-air. And I am going to lean into it. [laughs] JOËL: I like it. STEPHANIE: So, Joël, what's new in your world? JOËL: So, in a recent episode, I think it was two episodes ago, you shared an article by Maggie Appleton about tools for thought. And I've kind of been going back to that article a few times in the past few weeks. And I feel like I always see something new. And one tool for thought that Maggie explicitly mentions in the article is diagramming, and that's something that we've used as an industry for a long time to deal with conditional logic is just writing a flow diagram. And I feel like that's such a useful tool sometimes to move away from code and text into visuals and draw your problem rather than write your problem. It's often useful either when I'm trying to figure out how to structure some of my own code or when I'm reviewing a PR for somebody else, and something just feels not quite right, but I'm not quite sure what I want to say. And so drawing the problem all of a sudden might give me some insights, might help me identify why does something feel off about this code that I can't quite put into words? STEPHANIE: What does drawing complex things reveal for you? Is there a time where you were able to see something that you hadn't seen before? JOËL: One thing I think it can make more obvious is the shape of the problem. When we describe a problem in words, sometimes there's a sense of like, okay, there are two main paths through this problem or something. And then when we do our code, we try to make it DRY, and we try all these things. And it's really hard to see the flow of logic. And we might actually have way more paths through our code than are actually needed by the initial problem definition. I think we talked about this in a past episode as well, structuring a multi-step form or a wizard. And oftentimes, that is structured way more complex than it needs to be. And you can really see that difference when you draw out a flow diagram, the difference between forcing everything down a single linear flow with a bunch of little independent conditions versus branching up front three or four or five ways, however many steps you have. And then, from there, it's just executing code. STEPHANIE: I have two thoughts here. Firstly, it's very tragic that this is an audio medium only [laughs] and not also a visual one. Because I think we've joked in the past about when we've, you know, talked about complex problems and branching conditionals and stuff like that, like, oh, like, if only we could show a visual representation to our listeners. [laughs] And secondly, now that makes a lot more sense why there are so many whiteboards just hanging out in offices everywhere. [laughs] JOËL: We should use them more. It's interesting you mentioned the limitations of an audio format that we have. But even just describing the problem in an audio format is different than implementing it in code. So if I were to describe a problem to you that says, oh, we have a multi-step form that has three different steps to it, in that description, you might initially think, oh, that means I want to branch three ways up front, and then each step will need to do some processing. But if you look at the implementation in the code, maybe whoever coded it, and maybe that's yourself, will have done it totally differently with a lot more branching than just three up front because it's a different medium. STEPHANIE: That's a really good point. I also remember reading something about how you can reason about how many branches a piece of code might have if you just look at the structure of the lines of code in your editor if you either step away from it and are just looking at the code not really able to see the text itself but just the shape that it makes. If you have some shorter lines and then a handful of longer lines, you might be able to see like, oh, like these are multiple conditionals happening, which I think is kind of related to what you're saying about taking a piece of code and then diagramming it out to really see the different paths. And I know that that can also be obscured a little bit if you are stylistically using different syntax. Like, if you are using a guard clause to return early, that's a conditional, but it gets a bit hidden from the visual representation than if you had written out the full if statement, for example. JOËL: I think that's a really interesting distinction that you bring up because a lot of languages provide syntactic sugar for common conditional tasks that we do. And sometimes, that syntactic sugar will almost obfuscate the fact that there is a conditional happening at all, which can be great in a lot of cases. But when it comes to analyzing and particularly comparing different implementations, a second conversion that I like to do is converting all of the conditional code to some standardized form, and, for me, that's typically just your basic if...elsif...else expressions. And so any fancy Boolean operators we're doing, any safe navigation that we're doing around nil, maybe some inline conditionals, early returns, things like that, all of the implicit elses that are involved as well, putting them all into some normalized form then allows me to compare two implementations with each other. And sometimes, two approaches that we initially thought were identical, just with different syntax, turned out to have slightly different behavior because maybe one has this sort of implicit branch that the other one doesn't. And by converting to a normalized syntax, all of a sudden, this difference becomes super obvious. To be clear, this is not something I do necessarily in the actual code that I commit, not necessarily writing everything long-form. But definitely, when I'm trying to think about conditional code or analyzing somebody else's code, I will often convert it to long-form, some normalized shape so that I can then see some things about it that were not obvious in the final form. Or to make a comparison with something else, and then you can compare apples to apples and say, okay, both these approaches that we're considering in normalized form, here's what they look like. There's some difference here that we do care about or don't care about. STEPHANIE: That's really interesting. I find it very curious that there is a value in having the long-form approach of writing the code out and being able to identify things. But then the end result that we commit might not look like that and be shortened and be kind of, quote, unquote, "polished," or at least condensed with syntactic sugar. And I'm kind of wondering why that might be the case. JOËL: I think a lot of that will come down to your personal or your company's style guide. Personally, I think I do lean a little bit more towards a slightly more explicit form. But there are plenty of times that I will use syntactic sugar as well, as long as everybody knows what it does. But sometimes, it will come at the cost of other analysis techniques. You had mentioned the squint test earlier, which I believe is a term coined by Sandi Metz. STEPHANIE: I think it might be. That rings a bell. JOËL: And that is a benefit that you get by writing explicit conditionals all the time. But sometimes, it is much nicer to write code that is a little bit more terse. And so you have to do the trade-offs there. STEPHANIE: Yeah, that's a really good point. JOËL: So that's two of the sort of three formats that I was thinking about for converting conditional code to gain more insight. The other format is honestly a little bit weird. It's almost a stretch. But from my time spent working with the Elm language, I learned how to use its type system, which uses a concept called algebraic data types, or some languages will call these tagged unions, some languages will call these sum types. This concept goes by a lot of different names. But they're used to define types into model data. But there's a really fun property, which is that you can model conditional code using this as well. And so you can convert executable code into these algebraic data types. And now, you can apply a lot of tools and heuristics that you have from the data modeling world to this conditional code. STEPHANIE: Do you have a practical example? JOËL: So a classic thing that data modelers will say is you should make impossible states impossible. So in practice, this means that when you define a type using these algebraic data types, you should not be able to create more distinct values than are actually valid in this particular system. So, for example, if a value is required to always be present for something and there's no way in the system for a value to become not present, then don't allow it to be nullable. We do something similar when we design a database schema when we put a null false on a column because we know that this will never be null. And so, why allow nulls when you know they should never be there? So it's a similar thing with the types. This sort of analysis that you can do looking at...the fancy term is the types cardinality. I'll link to an article that digs into that for people who are curious. But that can show you whether a type can represent, let's say, ten possible values, but the domain you're trying to model only has 5. And so when there's that discrepancy, there are five valid values that can be modeled by your type and an additional extra five that are not valid that just kind of shake out from the way you implemented things. So you can take that technique and apply it to a conditional that you've converted to algebraic data type form. And that can help find things like paths through your conditional code that don't line up with the problem that you're trying to solve. So going back to the example I talked about earlier of a multi-step form with three different steps, that's a problem that should have three paths through your conditional. But depending on your implementation, if it's a bunch of independent if clauses, you might have a bit of a combinatorial explosion. And there might be 25 different paths through that chunk of code. And that means three of them are the ones that your problem wants, and then the extra 22 are things that should quote, unquote, "never happen," but we all know that they eventually will. So that kind of analysis can help maybe give you pointers to the fact that your current structure is not well-suited to the problem that you're trying to solve. STEPHANIE: I think another database schema example that came to mind for me was using an enum to declare acceptable values for a field. And, yeah, I know exactly what you mean when working with code where you might know, because of the way the business works, that this thing is impossible, and yet, you still have to either end up coding defensively for it or just kind of hold that complexity in your head. And that can lead to some gnarly situations, and it makes debugging down the line a lot more difficult too. JOËL: It definitely makes it really hard for somebody else to know the original intention of the code when a conditional has more paths through it than there actually are actual paths in the problem you're trying to solve. Because you have to load all of that in your head, and our programmer brains are trained to think about all the edge cases, and what if this condition fires but this other one doesn't? Could that lead to a bug? Is that just a thing that's like, well, but the inputs will never trigger that, so you can ignore it? And if there are no comments to tell you, and if there are comments, then do you trust them? Because it -- STEPHANIE: Yes. [laughter] I'll just jump in here and say, yeah, I have seen the comments then conflict with the code as well. And so you have these two sources of information that are conflicting with each other, and you have no idea what is true and what's not. JOËL: So I'm a big fan of structuring conditional code such that the number of unique paths through a set of conditions is the same as the sort of, you might say, logical paths through the problem domain that we haven't added extra paths, just sort of accidentally due to the way we implemented things. STEPHANIE: Yeah. And now you have three different ways to visualize that information in your head [laughs] with these mental models. JOËL: Right. So from taking code that is conditional code and then transforming it into one of these other representations, I don't always do all three, but there are tools that I have. And I can gain all sorts of new insights into that code by looking at it through a completely different lens. STEPHANIE: That's super cool. JOËL: So the last episode, you had mentioned that you were going to try a soup club. How did that turn out? STEPHANIE: It turned out great. It was awesome, the inaugural soup group. I had, I think, around eight people total. And I spent...right after work, I went straight to chopping celery [laughs] and onions and just soup prepping. And it was such a good time. I invited a different group of friends than normally come together, and that turned out really well. I think we all kind of had at least one thing in common, which was my goal was just to, you know, have my friends come together and meet new people too. And we had soup, and we had bread. Someone brought a spiced crispy chickpea appetizer that went really well inside of our ribollita vegetable bean soup. And then I had the perfect amount of leftovers. So after making a really big batch of food and spending quite a long time cooking, I wanted to make sure that everyone had their fill. But it was also pretty nice to have two servings left over that I could toss in the freezer just for me and as a reward for my hard work. And then it ended up working out really well because I went on vacation last week. And the night we got back home, we were like, "Oh, it's kind of late. What are we going to do for dinner?" And then I got to pull out the leftover soup from my freezer. And it was the perfect coming home from a big trip, and you have nothing in your fridge kind of deal. So it worked out well. JOËL: I guess that's the advantage of hosting is that you get to keep the leftovers. STEPHANIE: It's true. JOËL: You also have to, you know, make the soup. [laughs] STEPHANIE: Also true. [laughs] But like I said, it wasn't like I had so much soup that I was going to have to eat it every single day for the next week and a half. It was just the amount that I wanted. So I'm excited to keep doing this. I'm hoping to do the next soup group in the next week or two. And then some other folks even offered to host it for next time. So maybe we might experiment with doing a rotating thing. But yeah, it has definitely brought me joy through this winter. JOËL: That's so lovely. What else has been new in your world? STEPHANIE: I have a clarification to make from last week's episode. So last week, we were talking about hexagons and tessellation. And we had mentioned that hexagons and triangles were really strong shapes. And we mentioned that, oh yeah, you can see it in the natural world through honeycomb. And I've since learned that bees don't actually build the hexagon shape themselves. That was something that scientists did think to be true for a little bit, that bees were just geometrically inclined, but it turns out that the accepted theory for how honeycomb gets its shape is that bees build cylindrical cells that later transform into hexagons, which does have a lot of surface area for holding the honey, though the process itself is actually still debated by scientists. So there's some research that has supported the idea that it's formed through physical forces like the changing temperature of the wax that transforms it from a cylinder shape into a hexagon, though, yeah, apparently, the studies are still a bit inconclusive. And the last scientific paper I read about this, just to really get my facts straight [laughs], they were kind of exploring aspects of bee behavior that led to the hexagons eventually forming because that does require that the cylinders are perfectly the same size and are at least built in a hexagonal pattern, even though the cells themselves are not hexagons. JOËL: Fascinating. So it sounds like it's either a social thing where the bees do it based off of some behavior. Or if it's a physical thing, it's some sort of like hexagons are a natural equilibrium point that everything kind of trends to, and so as temperature changes, the beehive will naturally trend towards that. STEPHANIE: Yeah, exactly. I have a good friend who is a beekeeper, so I got to pick her brain a little bit about honeycomb. [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 in the past few episodes, we've talked about books we're reading, articles that we're reading. This is kind of turning into the Stephanie and Joël book club. STEPHANIE: I love it. JOËL: That got me thinking about things that I've read that were impactful in the past year. So I'm curious for both of us what might be, let's say, the top two or three most impactful articles that you read in 2022. Or maybe to put it another way, what are the top two or three articles that you reference the most in conversations with other people? STEPHANIE: So listeners might not know this, but I actually joined thoughtbot early last year in February. So I was coming into this new job, and I was so excited to be joining an organization with so many talented developers. And I was really excited to learn from everyone. So I kind of came in with really big goals around my technical growth. And the end of the year just passed, and I got to do a little bit of reflection. And I was quite proud of myself actually for all the things that I had learned and all the ways that I had grown. And I was reminded of this blog post that I think I had in the back of my mind around "Coachability" by Cate, and she talks about how coaching is different from mentorship. And she provides some really cool mental models for different ways of providing support to your teammates. Let's say mentorship is teaching someone how to swim, and maybe helping someone out with a task might be throwing them a life raft. Coaching is more like seeing someone in the water, but you are up on a bridge, and you are kind of seeing all of their surroundings. And you are identifying ways that they can help themselves. So maybe there's a branch, a tree branch, a few feet away from them. And can they go grab that tree branch? How can they help themselves? So I came to this new job at thoughtbot, and I had these really big goals. But I also knew that I wanted to lean on my new co-workers and just be able to not only learn the things that I was really excited to learn but also trust that they had my best interests in mind as well and for them to be able to point out things that could help my career growth. So the idea of coachability was really interesting to me because I had been coming from a workplace that had a really great feedback culture. But I think this article touches on what to do with feedback in a way that I hadn't seen before. So she also describes being coachable as having two axes, one of them being receptiveness to feedback and the other being actionability in response to feedback. So receptiveness is when you hear feedback; do you listen to it? Do you work through it? How does that feedback fit into your mental model of your goals and your skills? And then actionability is like, okay, what do you do with that? How do you change your behavior? How do you change the way you approach problems? And those two things in mind were really helpful in terms of understanding how I respond to feedback and how to really make the most of it when I receive it. Because there are times when I get feedback, and I don't know what to do with it, you know, maybe it just wasn't specific enough. And so, in that sense, I want to work on my actionability and figuring out, okay, someone said that testing would be a really great opportunity for me to learn. But what can I do to learn how to write better tests? And that might involve figuring that out on my own, like, what strategies work for me. Or that might involve asking them, being like, "What do you recommend?" So yeah, I had this really big year of growth. And I'm excited to keep this mental model in mind when I feel like I might be stuck and I'm not getting the growth that I want and using those axes to kind of determine how to move forward. JOËL: I think the first thing that comes to mind for me is the episode that you and I did a while back about the value of precise language. For example, you talked about the distinction between coaching and mentorship, which I think in sort of colloquial speech, we kind of use interchangeably. But having them both mean different things, and then being able to talk about those or at least analyze yourself through the lens of those two words, I think, is really valuable and may be helping to drive either insights or actions that you can take. And similarly, this idea of having two different axes for receptiveness versus...was it changeability you said was the other one? STEPHANIE: Actionability. JOËL: Actionability, I think, is really helpful when you're feeling stuck because now you can realize, oh, is it because I'm not accepting feedback or not getting good feedback? Or is it that I'm getting feedback, but it's hard to take action on it? So just all of a sudden, having those terms and having that mental model, that framework, I feel like equips me to engage with feedback in a way that is much more powerful than when we kind of used all those terms interchangeably. STEPHANIE: Yeah, exactly. I think that it's very well understood that feedback is important and having a good feedback culture is really healthy. But I think we don't always talk about the next step, which is what do you do with feedback? And with the help of this article, I've kind of come to realize that all feedback is valuable, but not all of it is good. And she makes a really excellent point of saying that the way you respond to feedback also depends on the relationship you have with the person giving it. So, ideally, you have a high trust high respect relationship with that person. And so when they give you feedback, you are like, yeah, I'm receptive to this, and I want to do something about it. But sometimes you get feedback from someone, and you might not have that trust in that relationship or that respect. And it just straight up might not be good feedback for you. And the way you engage with it could be figuring out what part of it is helpful for me and what part of it is not? And if it's not helpful in terms of helping your growth, it might at least be informative. And that might help you learn something about the other person or about the circumstances or environment that you're in. JOËL: Again, I love the distinction you're making between helpful and informative. STEPHANIE: Yeah. I think I had to learn that the hard way this year. [laughs] So, yeah, I really hope that folks find this vocabulary or this idea...or consider it when they are thinking about feedback in terms of giving it or receiving it and using it in a way that works for them to grow the way they want to. JOËL: I'm curious, in your interactions, and learning, and growth over the past year, do you feel like you've leaned a little bit more into the mentorship or the coaching side of things? What would you say is the rough percentage breakdown? Are we talking 50-50, 80-20? STEPHANIE: That's such a good question. I think I received both this year. But I think I'm at a point in my career where coaching is more valuable to me. And I'm reminded of a time a few months into joining thoughtbot where I was working and pairing with a principal developer. And he was really turning the workaround on me and asking, like, what do I want to do? What do I see in the code? What areas do I want to explore? And I found it really uncomfortable because I was like, oh, I just want you to tell me what to do because I don't know, or at least at the time, I was really...I found it kind of stressful. But now, looking back on it and with this vocabulary, I'm like, oh, that's what true coaching was because I gained a lot of experience towards my foundational skill set of figuring out how to solve problems or identifying areas of refactoring through that process. And so sometimes coaching can feel really uncomfortable because you are stretching outside of your comfort zone and that your coach is hopefully supporting you but not just giving you the help but teaching you how to help yourself. JOËL: That's a really interesting thing to notice. And I think what I'm hearing is that coaching can feel less comfortable than mentoring because you're being asked to do more of the work yourself. And you're maybe being stretched in some ways that aren't exactly the same as you would get in a more mentoring-focused scenario. Does that sound right? STEPHANIE: Yeah, I think that sounds right because, like I said, I was also receiving mentorship, and I learned about new things. But those didn't always solidify in terms of empowering me next time to be able to do it without the help of someone else. Joël, what was an article that really spoke to you this last year? JOËL: So I really appreciated an article by Adrianna Chang, who's a developer at Shopify, about "Refactoring Legacy Code with the Strangler Fig Pattern." And it talks about this approach to moving refactoring code from one implementation to another. And it's a longer-ranged process, and how to do so incrementally. And a big theme for me this year has been refactoring and incremental change. I've had a lot of conversations with people about how to spot smaller steps. I've written an article on working incrementally. And so I think this was really nice because it gave a very particular technique on how to do so with an example. And so, because these sorts of conversations kept coming up this year, I found myself referencing this article all the time. STEPHANIE: I really loved this article too. And this last year, I also saw a strangler fig tree for the first time in real life in Florida. And I think that was after I had read this article. And it was really cool to make the connection between something I was seeing in nature with a pattern in software development or technique. JOËL: We have this metaphor, and now you get to see the real thing. I was excited because, at RubyConf Mini this year, I actually got to meet Adrianna. So it was really cool. It's like, "Hey, I've been referencing your article all year. It's super cool to meet you in person." STEPHANIE: That's awesome. I love that, just being able to support members of the community. What I really liked about the approach this article advocated for is that it allowed developers to continue working. You don't have to halt everything and dedicate time to refactor and not get any new feature work done. And that's the beauty of the incremental approach that you were talking about earlier, where you can continue development. Sometimes that refactoring might be paused for some reason or another, but then you can pick back up where you left off. And that is really intriguing to me because I think this past year, I was working on a client where refactoring seemed like something we had to dedicate special time for. And it constantly became tough to prioritize and sell to stakeholders. Whereas if you incorporate it into the work and do it in a way that doesn't stop the show [laughs] from going on, it can work really well and work towards sustainability and maintenance, which is another thing that we've talked a lot about on the show. JOËL: Something that's really powerful, I think, with that technique is that it allows you to have all of the intermediate steps get merged into your main branch and get shipped. So you don't have to have this long-running branch with a big change that's constantly going stale, and you're having to keep in sync with the main branch. And, unfortunately, I've often seen even this sort of thing where you create a long-running branch for a big change, a big refactor, and eventually, it just gets abandoned, and you have not locked in any wins. STEPHANIE: Yeah, that's the worst of both worlds where you've dedicated time and resources and don't get the benefits of that work. I also liked that the strangler fig pattern kind of forces you to really understand the existing code. I think working with legacy code can be really challenging. And a lot of people don't like to do it because it involves a lot of spelunking and figuring out, okay, what's really going on. But in order to isolate the pieces to, you know, slowly start to stop making calls to the old code, it requires that you take a hard look at your legacy code and really figure it out. And I honestly think that that then informs the new code that you write to better support both the old feature and also any new features to come. JOËL: Definitely. The really nice thing about this pattern is that it also scales up and down. You can do this really small...even as part of a feature branch; maybe it's just part of your development process, even if you don't necessarily ship all of the intermediate steps. But it helps you work more incrementally and in a tighter scope. And then you can scale it up as big as changing out entire sections of a framework or...I think Adrianna's example is like switching out a data source. And so you can do some really large refactors. But then you could do it as well on just a small feature. I really like using this pattern anytime you're doing things like Rails upgrades, and you've got old gems that might not convert over where it's like, oh, the community abandoned this gem between Rails 4 and Rails 5. But now you need sort of a bridge to get over. And so I think that pattern is particularly powerful when doing something like a Rails upgrade. STEPHANIE: Very Cool. JOËL: So what would be a second article that was really impactful for you in the past year? STEPHANIE: So, speaking of refactoring, I really enjoyed a blog post called Finding Time to Refactor by a former thoughtboter, German Velasco. He makes a really great point that we should think of completeness in our work, not just when the code works as expected or meets the product requirements, but also when it is clear and maintainable. And so he really advocates for baking refactoring into just your normal development process. And like I said, that goes back to this idea that it can be incremental. It doesn't have to be separate or something that we do later, which is kind of what I had learned before coming to thoughtbot. So when I was also speaking about just my technical growth, this shift in philosophy, for me, was a really big part of that. And I just started kind of thinking and seeing ways to just do it in my regular process. And I think that has really helped me to feel better about my work and also see a noticeable improvement in the quality of my code. So he mentioned the three times that he makes sure to refactor, and that is one when he is practicing TDD and going through the red-green-refactor cycle. JOËL: It's in the name. STEPHANIE: [laughs] It really is. Two, when code is difficult to understand, so if he's coming in and fixing a bug and he pays the tax of trying to figure out confusing code, that's a really great opportunity to then reduce that caring cost for others by making it clear while you're in there, so leaving things better than you found it. And then three, when the existing design doesn't work. We, I think, have mentioned the adage, "Make the change easy, and then make the easy change." So if he's coming in to add a new feature and it's just not quite working, then that's a really good opportunity to refactor the existing design to support this new information or new concept. JOËL: I like those three scenarios. And I think that second one, in particular, resonated with me, the making things easier to understand. And in the sort of narrower sense of the word refactoring, traditionally, this means changing the structure of the code without changing its behavior. And I once had a situation where I was dealing with a series of early return expressions in a method that were all returning Booleans. And it was really hard because there were some unlesses, some ifs, some weird negation happening. And I just couldn't figure out what this code was doing. STEPHANIE: Did you draw a diagram? [laughs] JOËL: I did not. But it turns out this code was untested. And so I pretty much just tried, like, it took two Booleans as inputs and gave back a Boolean. So I just tried all the combinations, put it in, saw what it gave me out, and then wrote tests for them. And then realized that the test cases were telling me that this code was always returning false unless both inputs were true. And that's when it kind of hits me, it's like, wait a minute, this is Boolean AND. We've reimplemented Boolean AND with this convoluted set of conditional code. And so, at the end there, once I had that test coverage to feel confident, I went in and did a refactor where I changed the implementation. Instead of being...I think it was like three or four inline conditionals, just rewrote it as argument one and argument two, and that was much easier to read. STEPHANIE: That's a great point. Because the next time someone comes in here, and let's say they have to maybe add another condition or whatever, they're not just tacking on to this really confusing thing. You've hopefully made it easier for them to work with that code. And I also really appreciated, you know, I was mentioning how this article affected my thought process and how I approach development, but it's a really great one to share to then foster a culture of just continuous refactoring, I guess, is what I'm going to call it [laughs] and hopefully, avoiding having to do a massive rewrite or a massive effort to refactor. The phrase that comes to mind is many hands make light work. And if we all incorporated this into our process, perhaps we would just be working all around with more delightful code. Joël, do you have one more article that really stood out to you this year? JOËL: One that I think I really connected with this year is "Parse, Don't Validate" by Alexis King. Long-time listeners of the show will have heard me talk about this a little bit with Chris Toomey when he was a guest on the show this past fall. But the gist of the article is that the process of parsing is converting a broader type into a narrower type with the potential for errors. So traditionally, we think of this as turning a string which a string is very broad. All sorts of things are strings, and then you turn it into something else. So maybe you're parsing JSON. So you take a string of characters and try to turn it into a Ruby hash, but not all strings are valid hashes. So there's also the possibility for errors. And so, JSON.parse() could raise an error in Ruby. This idea, though, can be then expanded because, ideally, you don't want to just check that a value is valid for your stricter rules. You don't want to just check that a string is valid JSON and then pass the string along to the next person. You actually want to transform it. And then everybody else down the line can interact with that hash and not have to do a check again is this valid JSON? You've already validated that you've already converted it into a hash. You don't need to check that it's valid JSON again because, by the nature of being a hash, it's impossible for it to be invalid. Now, you might have some extra requirements on that hash. So maybe you require certain keys to be present and things like that. And I think that's where this idea gets even more powerful because then you can kind of layer this on top and have a second parsing step where you say, I'm going to parse this hash into, let's say, a shopping cart object. And so, not all Ruby hashes are valid shopping carts. And so you try to take a broader value and coerce it into a narrower value or transform it into a narrower value and potentially raise an error for those hashes that are not valid shopping carts. And then, whoever down the line gets a shopping cart object, you can just call items on it. You can call price on it. You don't need to check is this key present? Because now you have that certainty. STEPHANIE: This reminds me of when I was working with TypeScript in the summer of last year. And having come from a dynamically-typed language background, it was really challenging but also really interesting to me because we were also parsing JSON. But once we had transformed or parsed that data into this domain object, we had a lot more confidence about what we were working in. And all the functions we wrote down the line or used on the line, we could know for sure that, okay, it has these properties about it. And that really shaped the code we wrote. JOËL: So use the word confident here, which, for me, it's a keyword. And so you can now assume that certain properties are true because it's been checked once. That can be tricky if you don't actually do a transformation. If you're just sort of passing a raw value down, you'll often end up with code that is defensive that keeps rechecking the same conditions over and over. And you see this lot around nil in Ruby where somebody checks for a value for nil, and then inside that conditional, three or four other conditions deep, we recheck the same value for nil again, even though, in theory, it should not be nil at that point. And so by doing transformations like that, by parsing instead of just validating, we can ensure that we don't have to repeat those conditions. STEPHANIE: Yeah, I mean, that refers back to the analyzing conditional code that we spent a bit of time talking about at the beginning of this episode. Because I remember in that application, we render different components based on the status of this domain object. And there was a condition for when the status was something that was not expected. And then someone had left a comment that was like, technically, this should never happen. But I think that he had to add it to appease the compiler. And I think had we been able to better enforce those boundaries, had we been more thoughtful around our domain modeling, we could have figured out how to make sure that we weren't then introducing that ambiguity down the line. JOËL: I think it's interesting that you immediately went to talking about TypeScript here because TypeScript has a type system. And the "f, Don't Validate" article is written in Haskell, which is another typed language. And types are great for showing you exactly like, here's the boundary. On this side of it, it's a string, and on this side here, it's a richly-typed value that has been parsed. In Ruby, we don't have that, everything is duck-typed, but I think the principle still applies. It's a little bit more implicit, but there are zones of high or low assumptions about the data. So when I'm interacting directly with raw input from a third-party endpoint, I'm really only expecting some kind of raw string from the body of the response. It may or may not be valid. There are all sorts of checks I need to do to make sure I can do anything with it. So that is a very low assumption zone. Later on, in the business logic part of the code, I might expect that I can call a method on the object to get the price of a shopping cart or a list of items or something like that. Now I'm in a much higher assumption zone. And being self-aware about where we transition from low assumptions to high assumptions is, I think, a really key takeaway for how we interact with code in Ruby. Because, oftentimes, where that boundary is a little bit fuzzy or where we think it's in one place but it's actually in a different place is where bugs tend to cluster. STEPHANIE: Do you have any thoughts about how to adhere to those rules that we're making so we're not having to assume in a dynamically-typed language? JOËL: One way that I think is often helpful is trying to use richer objects and to not just rely on primitives all the time. So don't pass a business process a hash and be just like, trust me, I checked it; it's got the right keys because the day will come when you pass it a malformed hash and now we're going to have an error in the business process. And now we have a dilemma because do we want to start adding defensive checks in the business process to be like, oh, are all our keys that we expect present, things like that? Do we need to elsewhere in the code make sure we process the hash correctly? It becomes a little bit messy. And so, oftentimes, it might be better to say, don't pass a raw hash around. Create a domain object that has the actual method that you want, and pass that instead. STEPHANIE: Oh, sounds like a great opportunity to use the new data class in Ruby 3.2 that we talked about in an episode prior. JOËL: That's a great suggestion. I would definitely reach for something like that, I think, in a situation where I'm trying to model something a little bit richer than just a hash. STEPHANIE: I also think that there have been more trends around borrowing concepts from functional programming, and especially with the introduction of classes that represent nil or empty states, so instead of just using the default nil, having at least a bit of context around a nil what or an empty what. That then might have methods that either raise an error or just signal that something is wrong with the assumptions that we're making around the flexibility that we get from duck typing. I'm really glad that you proposed this topic idea for today's episode because it really represented a lot of themes that we have been discussing on the show in the past couple of months. And I am excited to maybe do this again in the future to just capture what's been interesting or inspiring for us throughout the year. 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: Thank you so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeeeeee!!!!!!!! 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.

YAGNI
Detailed commit messages w/ Chris Toomey

YAGNI

Play Episode Listen Later Nov 1, 2022 53:03


Chris Toomey on TwitterMatt Swanson on TwitterArrowsSagewell FinancialWrite Good Commit Messages by Blaming OthersThe seven rules of a good git commit messageDavid Hemphill - WIPHot OnesRussian Roulette and expected value 

The Bike Shed
359: Serializers

The Bike Shed

Play Episode Listen Later Oct 25, 2022 44:10


Chris Toomey is back! (For an episode.) He talks about what he's been up to since handing off the reins to Joël. He's been playing around with something at Sagewell that he enjoys. At the core of it? Serializers. Primalize gem (https://github.com/jgaskins/primalize) Derek's talk on code review (https://www.youtube.com/watch?v=PJjmw9TRB7s) Inertia.js (https://inertiajs.com/) Phantom types (https://thoughtbot.com/blog/modeling-currency-in-elm-using-phantom-types) io-ts (https://gcanti.github.io/io-ts/) dry-rb (https://dry-rb.org/) parse don't validate (https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/) value objects (http://wiki.c2.com/?ValueObject) broader perspective on parsing (https://thoughtbot.com/blog/a-broader-take-on-parsing) Enumerable#tally (https://medium.com/@baweaver/ruby-2-7-enumerable-tally-a706a5fb11ea) RubyConf mini (https://www.rubyconfmini.com/) where.missing (https://boringrails.com/tips/activerecord-where-missing-associations) 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. And today, I'm joined by a very special guest, former host Chris Toomey. CHRIS: Hi, Joël. Thanks for having me. JOËL: And together, we're here to share a little bit of what we've learned along the way. So, Chris, what's new in your world? CHRIS: Being on this podcast is new in my world, or everything old is new again, or something along those lines. But, yeah, thank you so much for having me back. It's a pleasure. Although it's very odd, it feels somehow so different and yet very familiar. But yeah, more generally, what's new in my world? I think this was probably in development as I was winding down my time as a host here on The Bike Shed, but I don't know that I ever got a chance to talk about it. There has been a fun sort of deep-in-the-weeds technical thing that we've been playing around with at Sagewell that I've really enjoyed. So at the core of it, we have serializers. So we take some data structures in our Ruby on Rails code base, and we need to serialize them to JSON to send them to the front end. In our case, we're using Inertia, so it's not quite a JSON API, but it's fine to think about it in that way for the context of this discussion. And what we were finding is our front end has TypeScript. So we're writing Svelte, which is using TypeScript. And so we're stating or asserting that the types like, hey, we're going to get this data in from the back end, and it's going to have this shape to it. And we found that it was really hard to keep those in sync to keep, like, what does the user mean on the front end? What's the data that we're going to get? It's going to have a full name, which is a string, except sometimes that might be null. So how do we make sure that those are keeping up to date? And then we had a growing number of serializers on the back end and determining which serializer we were actually using, and it was just...it was a mess, to put it lightly. And so we had explored a couple of different options around it, and eventually, we found a library called Primalize. So Primalize is a Ruby library. It is for writing JSON serializers. But what's really interesting about it is it has a typing layer. It's like a type system sort of thing at play. So when you define a serializer in Primalize, instead of just saying, here are the fields; there is an ID, a name, et cetera, you say, there is an ID, and it is a string. There is a name, and it is a string, or an optional string, which is the even more interesting bit. You can say array. You can say object. You can say an enum of a couple of different values. And so we looked at that, and we said, ooh, this is very interesting. Astute listeners will know that this is probably useless in a Ruby system, which doesn't have types or a compilation step or anything like that. But what's really cool about this is when you use a Primalize serializer, as you're serializing an object, if there is ever a type mismatch, so the observed type at runtime and the authored type if those ever mismatch, then you can have some sort of notification happen. So in our case, we configured it to send a warning to Sentry to say, "Hey, you said the types were this, but we're actually seeing this other thing." Most often, it will be like an Optional, a null sneaking through, a nil sneaking through on the Ruby side. But what was really interesting is as we were squinting at this, we're like, huh, so now we're going to write all this type information. What if we could somehow get that type information down to the front end? So I had a long weekend, one weekend, and I went away, and I wrote a bunch of code that took all of those serializers, ran through them, and generated the associated TypeScript interfaces. And so now we have a build step that will essentially run that and assert that we're getting the same thing in CI as we have committed to the codebase. But now we have the generated serializer types on the front end that match to the used serializer on the back end, as well as the observed run-time types. So it's a combination of a true compilation step type system on the front end and a run-time type system on the back end, which has been very, very interesting. JOËL: I have a lot of thoughts here. CHRIS: I figured you would. [laughs] JOËL: But the first thing that came to mind is, as a consultant, there's a scenario with especially smaller startups that generally concerns me, and that is the CTO goes away for a weekend and writes a lot of code... CHRIS: [laughs] JOËL: And brings in a new system on Monday, which is exactly what you're describing here. How do you feel about the fact that you've done that? CHRIS: I wasn't ready to go this deep this early on in this episode. JOËL: [laughs] CHRIS: But honestly, that is a fantastic question. It's a thing that I have been truly not struggling with but really thinking about. We're going to go on a slight aside here, but I am finding it really difficult to engage with the actual day-to-day coding work that we're doing and to still stay close to the codebase and not be in the way. There's a pattern that I've seen happen a number of times now where I pick up a piece of work that is, you know, one of the tickets at the top of the backlog. I start to work on it. I get pulled into a meeting, then another meeting, then three more meetings. And suddenly, it's three days later. I haven't completed this piece of work that was defined to be the next most important piece of work. And suddenly, I'm blocking the team. JOËL: Hmmm. CHRIS: So I actually made a rule that I'm not allowed to own critical path work, which feels weird because it's like, I want to be engaged with that work. So the counterpoint to that is I'm now trying to schedule pairing sessions with each of the developers on the team once a week. And in that time, I can work on that sort of stuff with them, and they'll then own it and run with it. So it makes sure that I'm not blocking on those sorts of things, but I'm still connected to the core work that we're doing. But the other thing that you're describing of the CTO goes away for the weekend and then comes back with a new harebrained scheme; I'm very sensitive to that, having worked on; frankly, I think the same project. I can think of a project that you and I worked on where we experienced this. JOËL: I think we're thinking of the same project. CHRIS: So yes. Like, I'm scarred by that and, frankly, a handful of experiences of that nature. So we actually, I think, have a really healthy system in place at Sagewell for capturing, documenting, prioritizing this sort of other work, this developer-centric work. So this is the feature and bug work that gets prioritized and one list over here that is owned by our product manager. Separately, the dev team gets to say, here are the pain points. Here's the stuff that keeps breaking. Here are the things that I wish was better. Here is the observability hard-to-understand bits. And so we have a couple of different systems at play and recurring meetings and sort of unique ceremonies around that, and so this work was very much a fallout of that. It was actually a recurring topic that we kept trying a couple of different stabs at, and we never quite landed it. And then I showed up this one Monday morning, and I was like, "I found a thing; what do we think?" And then, critically, from there, I made sure I paired with other folks on the team as we pushed on the implementation. And then, actually, I mentioned Primalize, the library that we're using. We have now since deprecated Primalize within the app because we kept just adding to it so much that eventually, we're like, at this point, should we own this stuff? So we ended up rewriting the core bits of Primalize to better fit our use cases. And now we've actually removed Primalize, wonderful library. I highly recommend it to anyone who has that particular use case but then the additional type generation for the front end. Plus, we have some custom types within our app, Money being the most interesting one. We decided to model Money as our first-class consideration rather than just letting JavaScript have the sole idea of a number. But yes, in a very long-winded way, yes, I'm very sensitive to the thing you described. And I hope, in this case, I did not fall prey to the CTO goes away for the weekend and made a thing. JOËL: I think what I'm hearing is the key difference here is that you got buy-in from the team around this idea before you went out and implemented it. So you're not off doing your own things disconnected from the team and then imposing it from on high. The team already agreed this is the thing we want to do, and then you just did it for them. CHRIS: Largely, yes. Although I will say there are times that each developer on the team, myself included, have sort of gone away, come back with something, and said, "Hey, here's a WIP PR exploring an area." And there was actually...I'm forgetting what the context was, but there was one that happened recently that I introduced. I was like; I had to do this. And the team talked me out of it, and I ended up closing that PR. Someone else actually made a different PR that was an alternative implementation. I was like, no, that's better; we should absolutely do that. And I think that's really healthy. That's a hard thing to maintain but making sure that everyone feels like they've got a strong voice and that we're considering all of the different ways in which we might consider the work. Most critically, you know, how does this impact users at the end of the day? That's always the primary consideration. How do we make sure we build a robust, maintainable, observable system, all those sorts of things? And primarily, this work should go in that other direction, but I also don't want to stifle that creative spark of I got this thing in my head, and I had to explore it. Like, we shouldn't then need to never mind, throw away the work, put it into a ticket. Like, for as long as we can, that more organic, intuitive process if we can retain that, I like that. Critically, with the ability for everyone to tell me, "No, this is a bad idea. Stop it. What are you doing?" And that has happened recently. I mean, they were kinder about it, but they did talk me out of a bad idea. So here we are. JOËL: So you showed up on Monday morning, not with telling everyone, "Hey, I merged this thing over the weekend." You're showing up with a work-in-progress PR. CHRIS: Yes, definitely. I mean, everything goes through a PR, and everything has discussion and conversation around it. That's a strong, strong like Derek Prior's wonderful talk Building a Culture of Code Review. I forget the exact name of it. But it's one of my favorite talks in talking about the utility of code review as a way to share ideas and all of those wonderful things. So everything goes through code review, and particularly anything that is of that more exploratory architectural space. Often we'll say any one review from anyone on the team is sufficient to merge most things but something like that, I would want to say, "Hey, can everybody take a look at this? And if anyone has any reservations, then let's talk about it more." But if I or anyone else on the team for this sort of work gets everybody approving it, then cool, we're good to go. But yeah, code review critical, critical part of the process. JOËL: I'm curious about Primalize, the gem that you mentioned. It sounds like it's some kind of validation layer between some Ruby data structure and your serializers. CHRIS: It is the serializer, but in the process of serializing, it does run-time type validation, essentially. So as it's accessing, you know, you say first name. You have a user object. You pass it in, and you say, "Serializer, there's a first name, and it's a string." It will call the first name method on that user object. And then, it will check that it has the expected type, and if it doesn't, then, in our case, it sends to Sentry. We have configured it...it's actually interesting. In development and test mode, it will raise for a type mismatch, and in production mode, it will alert Sentry so you can configure that differently. But that ends up being really nice because these type mismatches end up being very loud early on. And it's surprisingly easy to maintain and ends up telling us a lot of truths about our system because, really, what we're doing is connecting data from many different systems and flowing it in and out. And all of the inputs and outputs from our system feel very meaningful to lock down in this way. But yeah, it's been an adventure. JOËL: It seems to me there could almost be two sets of types here, the inputs coming into Primalize from your Ruby data structures and then the outputs that are the actual serialized values. And so you might expect, let's say, an integer on the Ruby side, but maybe at the serialization level, you're serializing it to a string. Do you have that sort of conversion step as part of your serializers sometimes, or is the idea that everything's already the right type on the Ruby side, and then we just, like, to JSON it at the end? CHRIS: Yep. Primalize, I think, probably works a little closer to what you're describing. They have the idea of coercions. So within Primalize, there is the concept of a timestamp; that is one of the types that is available. But a timestamp is sort of the union of a date, a time, or I think they might let through a string; I'm not sure if there is as well. But frankly, for us, that was more ambiguity than we wanted or more blurring across the lines. And in the implementation that we've now built, date and time are distinct. And critically, a string is not a valid date or time; it is a string, that's another thing. And so there's a bunch of plumbing within the way you define the serializers. There are override methods so that you can locally within the serializer say, like, oh, we need to coerce from the shape of data into this other shape of data, even little like in-line proc, so we can do it quickly. But the idea is that the data, once it has been passed to the serializer, should be up the right shape. And so when we get to the type assertion part of the library, we expect that things are in the asserted type and will warn if not. We get surprisingly few warnings, which is interesting now. This whole process has made us pay a little more intention, and it's been less arduous simultaneously than I would have expected because like this is kind of a lot of work that I'm describing. And yet it ends up being very natural when you're the developer in context, like, oh, I've been reading these docs for days. I know the shape of this JSON that I'm working with inside and out, and now I'll just write it down in the serializer. It's very easy to do in that moment, and then it captures it and enforces it in such a useful way. As an aside, as I've been looking at this, I'm like, this is just GraphQL, but inside out, I'm pretty sure. But that is a choice that we have made. We didn't want to adopt the whole GraphQL thing. But just for anyone out there who is listening and is thinking, isn't this just GraphQL but inside out? Kind of. Yes. JOËL: I think my favorite part of GraphQL is the schema, which is not really the selling point for GraphQL, you know, like the idea that you can traverse the graph and get any subset of data that you want and all that. I think I would be more than happy with a REST API that has some kind of schema built around it. And someone told me that maybe what I really just want is SOAP, and I don't know how to feel about that comment. CHRIS: You just got to have some XML, and some WSDLs, and other fun things. I've heard people say good things about SOAP. SOAP seems like a fine idea. If anything, I think a critical part of this is we don't have a JSON API. We have a very tightly coupled front end and back end, and a singular front end, frankly. And so that I think naturally...that makes the thing that I'm describing here a much more comfortable fit. If we had multiple different downstream clients that we're trying to consume from the same back end, then I think a GraphQL API or some other structured JSON schema, whatever it is type of API, and associated documentation and typing layer would be probably a better fit. But as I've said many a time on this here, Bike Shed, Inertia is one of my favorite libraries or frameworks (They're probably more of a framework.) one of my favorite technological approaches that I have ever found. And particularly in buildings Sagewell, it has allowed us to move so rapidly the idea that changes are, you know, one fell swoop changes everything within the codebase. We don't have to think about syncing deploys for the back end and the front end and how to coordinate across them. Our app is so much easier to understand by virtue of that architecture that Inertia implies. JOËL: So, if I understand correctly, you don't serialize to JSON as part of the serializers. You're serializing directly to JavaScript. CHRIS: We do serialize to JSON. At the end of the day, Inertia takes care of this on both the Rails side and the client side. There is a JSON API. Like, if you look at the network inspector, you will see XHR requests happening. But critically, we're not doing that. We're not the ones in charge of it. We're not hitting a specific endpoint. It feels as an application coder much closer to a traditional Rails app. It just happens to be that we're writing our view layer. Instead of an ERB, we're writing them in Svelte files. But otherwise, it feels almost identical to a normal traditional Rails app with controllers and the normal routing and all that kind of stuff. JOËL: One thing that's really interesting about JSON as an interchange format is that it is very restrictive. The primitives it has are even narrower than, say, the primitives that Ruby has. So you'd mentioned sending a date through. There is no JSON date. You have to serialize it to some other type, potentially an integer, potentially a string that has a format that the other side knows how it's going to interpret. And I feel like it's those sorts of richer types when we need to pass them through JSON that serialization and deserialization or parsing on the other end become really interesting. CHRIS: Yeah, I definitely agree with that. It was a struggling point for a while until we found this new approach that we're doing with the serializers in the type system. But so far, the only thing that we've done this with is Money. But on the front end, a while ago, we introduced a specific TypeScript type. So it's a phantom type, and I believe I'm getting this correct. It's a phantom type called Cents, C-E-N-T-S. So it represents...I'm going to say an integer. I know that JavaScript doesn't have integers, but logically, it represents an integer amount of cents. And critically, it is not a number, like, the lowercase number in the type system. We cannot add them together. We can't -- JOËL: I thought you were going to say, NaN. CHRIS: [laughs] It is not a number. I saw a n/a for not applicable somewhere in the application the other day. I was like, oh my God, we have a NaN? It happened? But it wasn't, it was just n/a, and I was fine. But yeah, so we have this idea of Cents within the application. We have a money input, which is a special input designed exactly for this. So to a user, it is formatted to look like you're entering dollars and cents. But under the hood, we are bidirectionally converting that to the integer amount of cents that we need. And we strictly, within the type system, those are cents. And you can't do math on Cents unless you use a special set of helper functions. You cannot generate Cents on the fly unless you use a special set of helper functions, the constructor functions. So we've been really restrictive about that, which was kind of annoying because a lot of the data coming from the server is just, you know, numbers. But now, with this type system that we've introduced on the Ruby side, we can assert and enforce that these are money.new on the Ruby side, so using the Money gem. And they come down to the front end as capital C Cents in the type system on the TypeScript side. So we're able to actually bind that together and then enforce proper usage sort of on both sides. The next step that we plan to do after that is dates and times. And those are actually almost weirder because they end up...we just have to sort of say what they are, and they will be ISO 8601 date and time strings, respectively. But we'll have functions that know this is a date string; that's a thing. It is, again, a phantom type implemented within our TypeScript type system. But we will have custom functions that deal with that and really constrain...lock ourselves down to only working with them correctly. And critically, saying that is the only date and time format that we work with; there is no other. We don't have arbitrary dates. Is this a JSON date or something else? I don't know; there are too many date syntaxes. JOËL: I like the idea of what you're doing in that it sounds like you're very much narrowing that sort of window of where in the stack the data exists in the sort of unstructured, free-floating primitives that could be misinterpreted. And so, at this point, it's almost narrowed to the point where it can't be touched by any user or developer-written code because you've pushed the boundaries on the Rails side down and then on the JavaScript side up to the point where the translation here you define translations on one side or, I guess, a parser on one side and a serializer on the other. And they guarantee that everything is good up until that point. CHRIS: Yep, with the added fun of the runtime reflection on the Ruby side. So it's an interesting thing. Like, TypeScript actually has similar things. You can say what the type is all day long, and your code will consistently conform to that asserted type. But at the end of the day, if your JSON API gets in some different data...unless you're using a library like io-ts, is one that I've looked at, which actually does parsing and returns a result object of did we parse to the thing that you wanted or did we get an error in that data structure? So we could get to that level on the client side as well. We haven't done that yet largely because we've essentially pushed that concern up to the Ruby layer. So where we're authoring the data, because we own that, we're going to do it at that level. There are a bunch of benefits of defining it there and then sort of reflecting it down. But yeah, TypeScript, you can absolutely lie to yourself, whereas Elm, a language that I know you love dearly, you cannot lie to yourself in Elm. You've got to tell the truth. It's the only option. You've got to prove it. Whereas in TypeScript, you can just kind of suggest, and TypeScript will be like, all right, cool, I'll make sure you stay honest on that, but I'm not going to make you prove it, which is an interesting sort of set of related trade-offs there. But I think we found a very comfortable resting spot for right now. Although now, we're starting to look at the edges of the Ruby system where data is coming in. So we have lots of webhooks and other external partners that we're integrating with, and they're sending us data. And that data is of varying shapes. Some will send us a payload with the word amount, and it refers to an integer amount of cents because, of course, it does. Some will send us the word amount in their payload, and it will be a floating amount of dollars. And I get a little sad on those days. But critically, our job is to make sure all of those are the same and that we never pass dollars as cents or cents as dollars because that's where things go sad. That is job number one at Sagewell in the engineering team is never get the decimal place wrong in money. JOËL: That would be a pretty terrible mistake to make. CHRIS: It would. I mean, it happens. In fintech, that problem comes up a lot. And again, the fact that...I'm honestly surprised to see situations out there where we're getting in floating point dollars. That is a surprise to me because I thought we had all agreed sort of as a community that it was integer cents but especially in a language that has integers. JavaScript, it's kind of making it up the whole time. But Ruby has integers. JSON, I guess, doesn't have integers, so I'm sort of mixing concerns here, but you get the idea. JOËL: Despite Ruby not having a static type system, I've found that generally, when I'm integrating with a third-party API, I get to the point where I want something that approximates like Elm's JSON decoders or io-ts or something like that. Because JSON is just a big blob of data that could be of any shape, and I don't really trust it because it's third-party data, and you should not trust third parties. And I find that I end up maybe cobbling something together commonly with like a bunch of usage of hash.fetch, things like that. But I feel like Ruby doesn't have a great approach to parsing and composing these validators for external data. CHRIS: Ruby as a language certainly doesn't, and the ecosystem, I would say, is rather limited in terms of the options here. We have looked a bit at the dry-rb stack of gems, so dry-validation and dry-schema, in particular, both offer potentially useful aspects. We've actually done a little bit of spiking internally around that sort of thing of, like, let's parse this incoming data instead of just coercing to hash and saying that it's got probably the shape that we want. And then similarly, I will fetch all day instead of digging because I want to be quite loud when we get it wrong. But we're already using dry-monads. So we have the idea of result types within the system. We can either succeed or fail at certain operations. And I think it's just a little further down the stack. But probably something that we will implement soon is at those external boundaries where data is coming in doing some form of parsing and validation to make sure that it conforms to unknown data structure. And then, within the app, we can do things more cleanly. That also would allow us to, like, let's push the idea that this is floating point dollars all the way out to the edge. And the minute it hits our system, we convert it into a money.new, which means that cents are properly handled. It's the same type of money or dollar, same type of currency handling as everywhere else in the app. And so pushing that to the very edges of our application is a very interesting idea. And so that could happen in the library or sort of a parsing client, I guess, is probably the best way to think about it. So I'm excited to do that at some point. JOËL: Have you read the article, Parse, Don't Validate? CHRIS: I actually posted that in some code review the other day to one of the developers on the team, and they replied, "You're just going to quietly drop one of my favorite articles of all time in code review?" [laughs] So yes, I've read it; I love it. It's a wonderful idea, definitely something that I'm intrigued by. And sort of bringing dry-monads into Ruby, on the one hand, feels like a forced fit and yet has also been one of the other, I think strongest sort of architectural decisions that we've made within the application. There's so much imperative work that we ended up having to do. Send this off to this external API, then tell this other one, then tell this other one. Put the whole thing in a transaction so that our local data properly handles it. And having dry-monads do notation, in particular, to allow us to make that manageable but fail in all the ways it needs to fail, very expressive in its failure modes, that's been great. And then parse, don't validate we don't quite do it yet. But that's one of the dreams of, like, our codebase really should do that thing. We believe in that. So let's get there soon. JOËL: And the core idea behind parse, don't validate is that instead of just having some data that you don't trust, running a check on it and passing that blob of now checked but still untrusted data down to the next person who might also want to check it. Generally, you want to pass it through some sort of filter that will, one, validate that it's correct but then actually typically convert it into some other trusted shape. In Ruby, that might be something like taking an amorphous blob of JSON and turning it into some kind of value object or something like that. And then anybody downstream that receives, let's say, money object can trust that they're dealing with a well-formed money value as opposed to an arbitrary blob of JSON, which hopefully somebody else has validated, but who knows? So I'm going to validate it again. CHRIS: You can tell that I've been out of the podcasting game for a while because I just started responding to yes; I love that blog post without describing the core premise of it. So kudos to you, Joël; you are a fantastic podcast host over there. I will say one of the things you just described is an interesting...it's been a bit of a struggle for us. We keep sort of talking through what's the architecture. How do we want to build this application? What do we care about? What are the things that really matter within this codebase, and then what is all the other stuff? And we've been good at determining the things that really matter, thinking collectively as a group, and I think coming up with some novel, useful, elegant...I'm saying too many positive adjectives for what we're doing. But I've been very happy with sort of the thing that we decide. And then there's the long-tail work of actually propagating that change throughout the rest of the application. We're, like, okay, here's how it works. Every incoming webhook, we now parse and yield a value object. That sentence that you just said a minute ago is exactly what I want. That's like a bunch of work. It's particularly a bunch of work to convert an existing codebase. It's easy to say, okay, from here forward, any new webhooks, payloads that are coming in, we're going to do in this way. But we have a lot of things in our app now that exist in this half-converted way. There was a brief period where we had three different serializer technologies at play. Just this week, I did the work of killing off the middle ground one, the Primalized-based thing, and we now have only our new hotness and then the very old. We were using Blueprinter as the serializer as the initial sort of stub. And so that still exists within the codebase in some places. But trying to figure out how to prioritize that work, the finishing out those maintenance-type conversions is a tricky one. It's never the priority. But it is really nice to have consistency in a codebase. So it's...yeah, do you have any thoughts on that? JOËL: I think going back to the article and what the meaning of parsing is, I used to always think of parsing as taking strings and turning them into something else, and I think this really broadened my perspective on the idea of parsing. And now, I think of it more as converting from a broader type to a narrower type with failures. So, for example, you could go from a string to an integer, and not all strings are valid integers. So you're narrowing the type. And if you have the string hello world, it will fail, and it will give you an error of some type. But you can have multiple layers of that. So maybe you have a string that you parse into an integer, but then, later on, you might want to parse that integer into something else that requires an integer in a range. Let's say it's a percentage. So you have a value object that is a percentage, but it's encoded in the JSON as a string. So that first pass, you parse it from a string into an integer, and then you parse that integer into a percentage object. But if it's outside the range of valid percentage numbers, then maybe you get an error there as well. So it's a thing that can happen at multiple layers. And I've now really connected it with the primitive obsession smell in code. So oftentimes, when you decide, wait, I don't want a primitive here; I want a richer type, commonly, there's going to be a parsing step that should exist to go from that primitive into the richer type. CHRIS: I like that. That was a classic Joël wildly concise summary of a deeply complex technical topic right there. JOËL: It's like I'm going to connect some ideas from functional programming and a classic object-oriented code smell and, yeah, just kind of mash it all together with a popular article. CHRIS: If only you had a diagram. Podcast is not the best medium for diagrams, but I think you could do it. You could speak one out loud, and everyone would be able to see it in their mind's eye. JOËL: So I will tell you what my diagram is for this because I've actually created it already. I imagine this as a sort of like pyramid with different layers that keep getting smaller and smaller. So the size of type is sort of the width of a layer. And so your strings are a very wide layer. Then on top of that, you have a narrower layer that might be, you know, it could be an integer, or you could even if you're parsing JSON, you first start with a string, then you parse that into a Ruby hash, not all strings are valid hashes. So that's going to be narrower. Then you might extract some values out of that hash. But if the keys aren't right, that might also fail. You're trying to pull the user out of it. And so each layer it gets a richer type, but that richer type, by virtue of being richer, is narrower. And as you're trying to move up that pyramid at every step, there is a possibility for a failure. CHRIS: Have you written a blog post about this with said diagram in it? And is that why you have that so readily at hand? [laughs] JOËL: Yes, that is the case. CHRIS: Okay. Yeah, that made sense to me. [laughs] JOËL: We'll make sure to link to it in the show notes. CHRIS: Now you have to link to Joël blog posts, whereas I used to have to link to them [chuckles] in almost every episode of The Bike Shed that I recorded. JOËL: Another thing I've been thinking about in terms of this parsing is that parsing and serializing are, in a sense, almost opposites of each other. Typically, when you're parsing, you're going from a broad type to a narrow one. And when you're serializing, you're going from a narrow type to a broader one. So you might go from a user into a hash into a string. So you're sort of going down that pyramid rather than going up. CHRIS: It is an interesting observation and one that immediately my brain is like, okay, cool. So can we reuse our serializers but just run them in reverse or? And then I try and talk myself out of that because that's a classic don't repeat yourself sort of failure mode of, like, actually, it's fine. You can repeat a little bit. So long as you can repeat and constrain, that's a fine version. But yeah, feels true, though, at the core. JOËL: I think, in some ways, if you want a single source of truth, what you want is a schema, and then you can derive serializers and parsers from that schema. CHRIS: It's interesting because you used the word derive. That has been an interesting evolution at Sagewell. The engineering team seems to be very collected around the idea of explicitness, almost the Zen of Python; explicit is better than implicit. And we are willing to write a lot of words down a lot of times and be happy with that. I think we actually made the explicit choice at one point that we will not implement an automatic camel case conversion in our serializer, even though we could; this is a knowable piece of code. But what we want is the grepability from the front end to the back end to say, like, where's this data coming from? And being able to say, like, it is this data, which is from this serializer, which comes from this object method, and being able to trace that very literally and very explicitly in the code, even though that is definitely the sort of thing that we could derive or automatically infer or have Ruby do that translation for us. And our codebase is more verbose and a little noisier. But I think overall, I've been very happy with it, and I think the team has been very happy. But it is an interesting one because I've seen plenty of teams where it is the exact opposite. Any repeated characters must be destroyed. We must write code to write the code for us. And so it's fun to be working with a team where we seem to be aligned around an approach on that front. JOËL: That example that you gave is really interesting because I feel like a common thing that happens in a serialization layer is also a form of normalization. And so, for example, you might downcase all strings as part of the serialization, definitely, like dates always get written in ISO 8601 format whenever that happens. And so, regardless of how you might have it stored on the Ruby side, by the time it gets to the JSON, it's always in a standard format. And it sounds like you're not necessarily doing that with capitalization. CHRIS: I think the distinction would be the keys and the values, so we are definitely doing normalization on the values side. So ISO 8601 date and time strings, respectively that, is the direction that we plan to go for the value. But then for the key that's associated with that, what is the name for this data, those we're choosing to be explicit and somewhat repetitive, or not even necessarily repetitive, but the idea of, like, it's first_name on the Ruby side, and it's first capital N name camel case, or it's...I forget the name. It's not quite camel case; it's a different one but lower camel, maybe. But whatever JavaScript uses, we try to bias towards that when we're going to the front end. It does get a little tricky coming back into the Ruby side. So our controllers have a bunch of places where they need to know about what I think is called lower camel case, and so we're not perfect there. But that critical distinction between sort of the names for things, and the values for things, transformations, and normalizations on the values, I'm good with that. But we've chosen to go with a much more explicit version for the names of things or the keys in JSON objects specifically. JOËL: One thing that can be interesting if you have a normalization phase in your serializer is that that can mean that your serializer and parsers are not necessarily symmetric. So you might accept malformed data into your parser and parse it correctly. But then you can't guarantee that the data that gets serialized out is going to identically match the data that got parsed in. CHRIS: Yeah, that is interesting. I'm not quite sure of the ramifications, although I feel like there are some. It almost feels like formatting Prettier and things like that where they need to hold on to whitespace in some cases and throw out in others. I'm thinking about how ASTs work. And, I don't know, there's interesting stuff, but, again, not sure of the ramifications. But actually, to flip the tables just a little bit, and that's an aggressive terminology, but we're going to roll with it. To flip the script, let's go with that, Joël; what's been up in your world? You've been hosting this wonderful show. I've listened in to a number of episodes. You're doing a fantastic job. I want to hear a little bit more of what's new in your world, Joël. JOËL: So I've been working on a project that has a lot of flaky tests, and we're trying to figure out the source of that flakiness. It's easy to just dive into, oh, I saw a flaky Test. Let me try to fix it. But we have so much flakiness that I want to go about it a little bit more systematically. And so my first step has actually been gathering data. So I've actually been able to make API requests to our CI server. And the way we figure out flakiness is looking at the commit hash that a particular test suite run has executed on. And if there's more than one CI build for a given commit hash, we know that's probably some kind of flakiness. It could be a legitimate failure that somebody assumed was flakiness, and so they just re-run CI. But the symptom that we are trying to address is the fact that we have a very high level of people re-verifying their code. And so to do that or to figure out some stats, I made a request to the API grouped by commit hash and then was able to get the stats of how many re-verifications there are and even the distribution. The classic way that you would do that is in Ruby; you would use the GroupBy function from enumerable. And then, you would transform values instead of having, like, say; each commit hash then points to all the builds, an array of builds that match that commit hash. You would then thumb those. So now you have commit hashes that point to counts of how many builds there were for that commit hash. Newer versions of Ruby introduced the tally method, which I love, which allows you to basically do all of that in one step. One thing that I found really interesting, though, is that that will then give me a hash of commit hashes that point to the number of builds that are there. If I want to get the distribution for the whole project over the course of, say, the last week, and I want to say, "How many times do people run only one CI run versus running twice in the same commit versus running three times, or four times, or five or six times?" I want to see that distribution of how many times people are rerunning their build. You're effectively doing that tally process twice. So once you have a list of all the builds, you group by hash. You count, and so you end up with that. You have the Ruby hash of commit SHAs pointing to number of times the build was run on that. And then, you again group by the number of builds for each commit SHA. And so now what you have is you'll have something like one, and then that points to an array of SHA one, SHA two, SHA three, SHA four like all the builds. And then you tally that again, or you transform values, or however, you end up doing it. And what you end up with is saying for running only once, I now have 200 builds that ran only once. For running twice in the same commit SHA, there are 15. For running three times, there are two. For running four times, there is one. And now I've got my distribution broken down by how many times it was run. It took me a while to work through all of that. But now the shortcut in my head is going to be you double tally to get distribution. CHRIS: As an aside, the whole everything you're talking about is interesting and getting to that distribution. I feel like I've tried to solve that problem on data recently and struggled with it. But particularly tally, I just want to spend a minute because tally is such a fantastic addition to the Ruby standard library. I used to have in sort of like loose muscle memory transform value is grouped by ampersand itself, transform values count, sort, reverse to H. That whole string of nonsense gets replaced by tally, and, oof, what a beautiful example of Ruby, and enumerable, and all of the wonder that you can encapsulate there. JOËL: Enumerable is one of the best parts of Ruby. I love it so much. It was one of the first things that just blew my mind about Ruby when I started. I came from a PHP, C++ background and was used to writing for loops for everything and not the nice for each loops that a lot of languages have these days. You're writing like a legit for or while loop, and you're managing the indexes yourself. And there's so much room for things to go wrong. And being introduced to each blew my mind. And I was like, this is so beautiful. I'm not dealing with indexes. I'm not dealing with the raw implementation of the array. I can just say do a thing for each element. This is amazing. And that is when I truly fell in love with Ruby. CHRIS: I want to say I came from Python, most recently before Ruby. And Python has pretty nice list comprehensions and, in fact, in some ways, features that enumerable doesn't have. But, still, coming to Ruby, I was like, oh, this enumerable; this is cool. This is something. And it's only gotten better. It still keeps growing, and the idea of custom enumerables. And yeah, there's some real neat stuff in there. JOËL: I'm going to be speaking at RubyConf Mini this fall in November, and my talk is all about Enumerators and ranges in enumerable and ways you can use those to make the APIs of the objects that you create delightful for other people to use. CHRIS: That sounds like a classic Joël talk right there that I will be happy to listen to when it comes out. A very quick related, a semi-related aside, so, tally, beautiful addition to the Ruby language. On the Rails side, there was one that I used recently, which is where.missing. Have you seen where.missing? JOËL: I have not heard of this. CHRIS: So where.missing is fantastic. Let's assume you've got two related objects, so you've got like a has many blah, so like a user has many posts. I think you can...if I'm remembering it correctly, it's User.where.missing(:posts). So it's where dot missing and then parentheses the symbol posts. And under the hood, Rails will do the whole LEFT OUTER JOIN where the count is null, et cetera. It turns into this wildly complex SQL query or understandably complex, but there's a lot going on there. And yet it compresses down so elegantly into this nice, little ActiveRecord bit. So where.missing is my new favorite addition into the Rails landscape to complement tally on the Ruby side, which I think tally is Ruby 2.7, I want to say. So it's been around for a while. And where.missing might be a Ruby 7 feature. It might be a six-something, but still, wonderful features, ever-evolving these tool sets that we use. JOËL: One of the really nice things about enumerable and family is the fact that they build on a very small amount of primitives, and so as long as you basically understand blocks, you can use enumerable and anything in there. It's not special syntax that you have to memorize. It's just regular functions and blocks. Well, Chris, thank you so much for coming back for a visit. It's been a pleasure. And it's always good to have you share the cool things that you're doing at Sagewell. CHRIS: Well, thank you so much, Joël. It's been an absolute pleasure getting to come back to this whole Bike Shed. And, again, just to add a note here, you're doing a really fantastic job with the show. It's been interesting transitioning back into listener mode for the show. Weirdly, I wasn't listening when I was a host. But now I've regained the ability to listen to The Bike Shed and really enjoy the episodes that you've been doing and the wonderful spectrum of guests that you've had on and variety of topics. So, yeah, thank you for hosting this whole Bike Shed. It's been great. JOËL: And with that, let's wrap up. The show notes for this episode can be found at bikeshed.fm. This show is produced and edited by Mandy Moore. 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. If you have any feedback, you can reach us at @_bikeshed, or reach me at @joelquen on Twitter, or at hosts@bikeshed.fm via email. Thank you so much for listening to The Bike Shed, and we'll see you next week. Byeeeeeeeeeee!!!!!!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

Closing Bell
Closing Bell Overtime: Snap Cracks 10/20/22

Closing Bell

Play Episode Listen Later Oct 20, 2022 44:29 Very Popular


Another earnings report from Snap, another slide in the stock. SoFi's Liz Young, Truist's Keith Lerner and NewEdge's Cameron Dawson dig into the quarter hot off the results. Plus, Wharton's Jeremy Siegel lays out his expectations for the Fed and inflation as yields hit new highs. And, top private wealth manager Chris Toomey of Morgan Stanley gives viewers a sneak peek into his year-end playbook.

The Bike Shed
355: Test Performance

The Bike Shed

Play Episode Listen Later Sep 20, 2022 42:44


Guest Geoff Harcourt, CTO of CommonLit, joins Joël to talk about a thing that comes up with a lot with clients: the performance of their test suite. It's often a concern because with test suites, until it becomes a problem, people tend to not treat it very well, and people ask for help on making their test suites faster. Geoff shares how he handles a scenario like this at CommonLit. 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. Geoff Harcourt (https://twitter.com/geoffharcourt) Common Lit (https://www.commonlit.org/) Cuprite driver (https://cuprite.rubycdp.com/) Chrome DevTools Protocol (CDP) (https://chromedevtools.github.io/devtools-protocol/) Factory Doctor (https://test-prof.evilmartians.io/#/profilers/factory_doctor) Joël's RailsConf talk (https://www.youtube.com/watch?v=LOlG4kqfwcg) Formal Methods (https://www.hillelwayne.com/post/formally-modeling-migrations/) Rails multi-database support (https://guides.rubyonrails.org/active_record_multiple_databases.html) Knapsack pro (https://knapsackpro.com/) Prior episode with Eebs (https://www.bikeshed.fm/353) Shopify article on skipping specs (https://shopify.engineering/spark-joy-by-running-fewer-tests) 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. And today, I'm joined by Geoff Harcourt, who is the CTO of CommonLit. GEOFF: Hi, Joël. JOËL: And together, we're here to share a little bit of what we've learned along the way. Geoff, can you briefly tell us what is CommonLit? What do you do? GEOFF: CommonLit is a 501(c)(3) non-profit that delivers a literacy curriculum in English and Spanish to millions of students around the world. Most of our tools are free. So we take a lot of pride in delivering great tools to teachers and students who need them the most. JOËL: And what does your role as CTO look like there? GEOFF: So we have a small engineering team. There are nine of us, and we run a Rails monolith. I'd say a fair amount of the time; I'm hands down in the code. But I also do the things that an engineering head has to do, so working with vendors, and figuring out infrastructure, and hiring, and things like that. JOËL: So that's quite a variety of things that you have to do. What is new in your world? What's something that you've encountered recently that's been fun or interesting? GEOFF: It's the start of the school year in America, so traffic has gone from a very tiny amount over the summer to almost the highest load that we'll encounter all year. So we're at a new hosting provider this fall. So we're watching our infrastructure and keeping an eye on it. The analogy that we've been using to describe this is like when you set up a bunch of plumbing, it looks like it all works, but until you really pump water through it, you don't see if there are any leaks. So things are in good shape right now, but it's a very exciting time of year for us. JOËL: Have you ever done some actual plumbing yourself? GEOFF: I am very, very bad at home repair. But I have fixed a toilet or two. I've installed a water filter but nothing else. What about you? JOËL: I've done a little bit of it when I was younger with my dad. Like, I actually welded copper pipes and that kind of thing. GEOFF: Oh, that's amazing. That's cool. Nice. JOËL: So I've definitely felt that thing where you turn the water source back on, and it's like, huh, let's see, is this joint going to leak, or are we good? GEOFF: Yeah, they don't have CI for plumbing, right? JOËL: [laughs] You know, test it in production, right? GEOFF: Yeah. [laughs] So we're really watching right now traffic starting to rise as students and teachers are coming back. And we're also figuring out all kinds of things that we want to do to do better monitoring of our application, so some of this is watching metrics to see if things happen. But some of this is also doing some simulated user activity after we do deploys. So we're using some automated browsers with Cypress to log into our application and do some user flows, and then report back on the results. JOËL: So is this kind of like a feature test in CI, except that you're running it in production? GEOFF: Yeah. Smoke test is the word that we've settled on for it, but we run it against our production server every time we deploy. And it's a small suite. It's nowhere as big as our big Capybara suite that we run in CI, but we're trying to get feedback in less than six minutes. That's sort of the goal. In addition to running tests, we also take screenshots with a tool called Percy, and that's a visual regression testing tool. So we get to see the screenshots, and if they differ by more than one pixel, we get a ping that lets us know that maybe our CSS has moved around or something like that. JOËL: Has that caught some visual bugs for you? GEOFF: Definitely. The state of CSS at CommonLit was very messy when I arrived, and it's gotten better, but it still definitely needs some love. There are some false positives, but it's been really, really nice to be able to see visual changes on our production pages and then be able to approve them or know that there's something we have to go back and fix. JOËL: I'm curious, for this smoke test suite, how long does it take to run? GEOFF: We run it in parallel. It runs on Buildkite, which is the same tool that we use to orchestrate our CI, and the longest test takes about five minutes. It signs in as a teacher, creates an account. It creates a class; it invites the student to that class. It then logs out, logs in as that student creates the student account, signs in as the student, joins the class. It then assigns a lesson to the student then the student goes and takes the lesson. And then, when the student submits the lesson, then the test is over. And that confirms all of the most critical flows that we would want someone to drop what they were doing if it's broken, you know, account creation, class creation, lesson creation, and students taking a lesson. JOËL: So you're compressing the first few weeks of school into five minutes. GEOFF: Yes. And I pity the school that has thousands of fake teachers, all named Aaron McCarronson at the school. JOËL: [laughs] GEOFF: But we go through and delete that data every once in a while. But we have a marketer who just started at CommonLit maybe a few weeks ago, and she thought that someone was spamming our signup form because she said, "I see hundreds of teachers named Aaron McCarronson in our user list." JOËL: You had to admit that you were the spammer? GEOFF: Yes, I did. [laughs] We now have some controls to filter those people out of reports. But it's always funny when you look at the list, and you see all these fake people there. JOËL: Do you have any rate limiting on your site? GEOFF: Yeah, we do quite a bit of it, actually. Some of it we do through Cloudflare. We have tools that limit a certain flow, like people trying to credential stuffing our password, our user sign-in forms. But we also do some further stuff to prevent people from hitting key endpoints. We use Rack::Attack, which is a really nice framework. Have you had to do that in client work with clients setting that stuff up? JOËL: I've used Rack:Attack before. GEOFF: Yeah, it's got a reasonably nice interface that you can work with. And I always worry about accidentally setting those things up to be too sensitive, and then you get lots of stuff back. One issue that we sometimes find is that lots of kids at the same school are sharing an IP address. So that's not the thing that we want to use for rate limiting. We want to use some other criteria for rate limiting. JOËL: Right, right. Do you ever find that you rate limit your smoke tests? Or have you had to bypass the rate limiting in the smoke tests? GEOFF: Our smoke tests bypass our rate limiting and our bot detection. So they've got some fingerprints they use to bypass that. JOËL: That must have been an interesting day at the office. GEOFF: Yes. [laughter] With all of these things, I think it's a big challenge to figure out, and it's similar when you're making tests for development, how to make tests that are high signal. So if a test is failing really frequently, even if it's testing something that's worthwhile, if people start ignoring it, then it stops having value as a piece of signal. So we've invested a ton of time in making our test suite as reliable as possible, but you sometimes do have these things that just require a change. I've become a really big fan of...there's a Ruby driver for Capybara called Cuprite, and it doesn't control chrome with Chrome Driver or with Selenium. It controls it with the Chrome DevTools protocol, so it's like a direct connection into the browser. And we find that it's very, very fast and very, very reliable. So we saw that our Capybara specs got significantly more reliable when we started using this as our driver. JOËL: Is this because it's not actually moving the mouse around and clicking but instead issuing commands in the background? GEOFF: Yeah. My understanding of this is a little bit hazy. But I think that Selenium and ChromeDriver are communicating over a network pipe, and sometimes that network pipe is a little bit lossy. And so it results in asynchronous commands where maybe you don't get the feedback back after something happens. And CDP is what Chrome's team and I think what Puppeteer uses to control things directly. So it's great. And you can even do things with it. Like, you can simulate different time zone for a user almost natively. You can speed up or slow down the traveling of time and the direction of time in the browser and all kinds of things like that. You can flip it into mobile mode so that the device reports that it's a touch browser, even though it's not. We have a set of mobile specs where we flip it with CDP into mobile mode, and that's been really good too. Do you find when you're doing client work that you have a demand to build mobile-specific specs for system tests? JOËL: Generally not, no. GEOFF: You've managed to escape it. JOËL: For something that's specific to mobile, maybe one or two tests that have a weird interaction that we know is different on mobile. But in general, we're not doing the whole suite under mobile and the whole suite under desktop. GEOFF: When you hand off a project...it's been a while since you and I have worked together. JOËL: For those who don't know, Geoff used to be with us at thoughtbot. We were colleagues. GEOFF: Yeah, for a while. I remember my very first thoughtbot Summer Summit; you gave a really cool lightning talk about Eleanor of Aquitaine. JOËL: [laughs] GEOFF: That was great. So when you're handing a project off to a client after your ending, do you find that there's a transition period where you're educating them about the norms of the test suite before you leave it in their hands? JOËL: It depends a lot on the client. With many clients, we're working alongside an existing dev team. And so it's not so much one big handoff at the end as it is just building that in the day-to-day, making sure that we are integrating with the team from the outset of the engagement. So one thing that does come up a lot with clients is the performance of their test suite. That's often a concern because the test suite until it becomes a problem, people tend to not treat it very well. And by the time that you're bringing on an external consultant to help, generally, that's one of the areas of the code that's been a little bit neglected. And so people ask for help on making their test suite faster. Is that something that you've had to deal with at CommonLit as well? GEOFF: Yeah, that's a great question. We have struggled a lot with the speed that our test suite...the time it takes for our test suite to run. We've done a few things to improve it. The first is that we have quite a bit of caching that we do in our CI suite around dependencies. So gems get cached separately from NPM packages and browser assets. So all three of those things are independently cached. And then, we run our suites in parallel. Our Jest specs get split up into eight containers. Our Ruby non-system tests...I'd like to say unit tests, but we all know that some of those are actually integration tests. JOËL: [laughs] GEOFF: But those tests run in 15 containers, and they start the moment gems are built. So they don't wait for NPM packages. They don't wait for assets. They immediately start going. And then our system specs as soon as the assets are built kick off and start running. And we actually run that in 40 parallel containers so we can get everything finished. So our CI suite can finish...if there are no dependency bumps and no asset bumps, our specs suite you can finish in just under five minutes. But if you add up all of that time, cumulatively, it's something like 75 minutes is the total execution as it goes. Have you tried FactoryDoctor before for speeding up test suites? JOËL: This is the gem from Evil Martians? GEOFF: Yeah, it's part of TestProf, which is their really, really unbelievable toolkit for improving specs, and they have a whole bunch of things. But one of them will tell you how many invocations of FactoryBot factories each factory got. So you can see a user factory was fired 13,000 times in the test suite. It can even do some tagging where it can go in and add metadata to your specs to show which ones might be candidates for optimization. JOËL: I gave a talk at RailsConf this year titled Your Tests Are Making Too Many Database Calls. GEOFF: Nice. JOËL: And one of the things I talked about was creating a lot more data via factories than you think that you are. And I should give a shout-out to FactoryProf for finding those. GEOFF: Yeah, it's kind of a silent killer with the test suite, and you really don't think that you're doing a whole lot with it, and then you see how many associations. How do you fight that tension between creating enough data that things are realistic versus the streamlining of not creating extraneous things or having maybe mystery guests via associations and things like that? JOËL: I try to have my base factories be as minimal as possible. So if there's a line in there that I can remove, and the factory or the model still saves, then it should be removed. Some associations, you can't do that if there's a foreign key constraint, and so then I'll leave it in. But I am a very hardcore minimalist, at least with the base factory. GEOFF: I think that makes a lot of sense. We use foreign keys all over the place because we're always worried about somehow inserting student data that we can't recover with a bug. So we'd rather blow up than think we recorded it. And as a result, sometimes setting up specs for things like a student answering a multiple choice question on a quiz ends up being this sort of if you give a mouse a cookie thing where it's you need the answer options. You need the question. You need the quiz. You need the activity. You need the roster, the students to be in the roster. There has to be a teacher for the roster. It just balloons out because everything has a foreign key. JOËL: The database requires it, but the test doesn't really care. It's just like, give me a student and make it valid. GEOFF: Yes, yeah. And I find that that challenge is really hard. And sometimes, you don't see how hard it is to enforce things like database integrity until you have a lot of concurrency going on in your application. It was a very rude surprise to me to find out that browser requests if you have multiple servers going on might not necessarily be served in the order that they were made. JOËL: [laughs] So you're talking about a scenario where you're running multiple instances of your app. You make two requests from, say, two browser tabs, and somehow they get served from two different instances? GEOFF: Or not even two browser tabs. Imagine you have a situation where you're auto-saving. JOËL: Oooh, background requests. GEOFF: Yeah. So one of the coolest features we have at CommonLit is that students can annotate and highlight a text. And then, the teachers can see the annotations and highlights they've made, and it's actually part of their assignment often to highlight key evidence in a passage. And those things all fire in the background asynchronously so that it doesn't block the student from doing more stuff. But it also means that potentially if they make two changes to a highlight really quickly that they might arrive out of order. So we've had to do some things to make sure that we're receiving in the right order and that we're not blowing away data that was supposed to be there. Just think about in a Heroku environment, for example, which is where we used to be, you'd have four dynos running. If dyno one takes too long to serve the thing for dyno two, request one may finish after request two. That was a very, very rude surprise to learn that the world was not as clean and neat as I thought. JOËL: I've had to do something similar where I'm making a bunch of background requests to a server. And even with a single dyno, it is possible for your request to come back out of order just because of how TCP works. So if it's waiting for a packet and you have two of these requests that went out not too long before each other, there's no guarantee that all the packets for request one come back before all the packets from request two. GEOFF: Yeah, what are the strategies for on the client side for dealing with that kind of out-of-order response? JOËL: Find some way to effectively version the requests that you make. Timestamp is an easy one. Whenever a request comes in, you take the response from the latest timestamp, and that wins out. GEOFF: Yeah, we've started doing some unique IDs. And part of the unique ID is the browser's timestamp. We figure that no one would try to hack themselves and intentionally screw up their own data by submitting out of order. JOËL: Right, right. GEOFF: It's funny how you have to pick something to trust. [laughs] JOËL: I'd imagine, in this case, if somebody did mess around with it, they would really only just be screwing up their own UI. It's not like that's going to then potentially crash the server because of something, and then you've got a potential vector for a denial of service. GEOFF: Yeah, yeah, that's always what we're worried about, and we have to figure out how to trust these sorts of requests as what's a valid thing and what is, as you're saying, is just the user hurting themselves as opposed to hurting someone else's stuff? 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! GEOFF: You were talking about test suites. What are some things that you have found are consistently problems in real-world apps, but they're really, really hard to test in a test suite? JOËL: Difficult to test or difficult to optimize for performance? GEOFF: Maybe difficult to test. JOËL: Third-party integrations. Anything that's over the network that's going to be difficult. Complex interactions that involve some heavy frontend but then also need a lot of backend processing potentially with asynchronous workers or something like that, there are a lot of techniques that we can use to make all those play together, but that means there's a lot of complexity in that test. GEOFF: Yeah, definitely. I've taken a deep interest in what I'm sure there's a better technical term for this, but what I call network hostile environments or bandwidth hostile environments. And we see this a lot with kids. Especially during the pandemic, kids would often be trying to do their assignments from home. And maybe there are five kids in the house, and they're all trying to do their homework at the same time. And they're all sharing a home internet connection. Maybe they're in the basement because they're trying to get some peace and quiet so they can do their assignment or something like that. And maybe they're not strongly connected. And the challenge of dealing with intermittent connectivity is such an interesting problem, very frustrating but very interesting to deal with. JOËL: Have you explored at all the concept of Formal Methods to model or verify situations like that? GEOFF: No, but I'm intrigued. Tell me more. JOËL: I've not tried it myself. But I've read some articles on the topic. Hillel Wayne is a good person to follow for this. GEOFF: Oh yeah. JOËL: But it's really fascinating when you'll see, okay, here are some invariants and things. And then here are some things that you set up some basic properties for a system. And then some of these modeling languages will then poke holes and say, hey, it's possible for this 10-step sequence of events to happen that will then crash your server. Because you didn't think that it's possible for five people to be making concurrent requests, and then one of them fails and retries, whatever the steps are. So it's really good at modeling situations that, as developers, we don't always have great intuition, things like parallelism. GEOFF: Yeah, that sounds so interesting. I'm going to add that to my list of reading for the fall. Once the school year calms down, I feel like I can dig into some technical topics again. I've got this book sitting right next to my desk, Designing Data-Intensive Applications. I saw it referenced somewhere on Twitter, and I did the thing where I got really excited about the book, bought it, and then didn't have time to read it. So it's just sitting there unopened next to my desk, taunting me. JOËL: What's the 30-second spiel for what is a data-intensive app, and why should we design for it differently? GEOFF: You know, that's a great question. I'd probably find out if I'd dug further into the book. JOËL: [laughs] GEOFF: I have found at CommonLit that we...I had a couple of clients at thoughtbot that dealt with data at the scale that we deal with here. And I'm sure there are bigger teams doing, quote, "bigger data" than we're doing. But it really does seem like one of our key challenges is making sure that we just move data around fast enough that nothing becomes a bottleneck. We made a really key optimization in our application last year where we changed the way that we autosave students' answers as they go. And it resulted in a massive increase in throughput for us because we went from trying to store updated versions of the students' final answers to just storing essentially a draft and often storing that draft in local storage in the browser and then updating it on the server when we could. And then, as a result of this, we're making key updates to the table where we store a student's answers much less frequently. And that has a huge impact because, in addition to being one of the biggest tables at CommonLit...it's got almost a billion recorded answers that we've gotten from students over the years. But because we're not writing to it as often, it also means that reads that are made from the table, like when the teacher is getting a report for how the students are doing in a class or when a principal is looking at how a school is doing, now, those queries are seeing less contention from ongoing writes. And so we've seen a nice improvement. JOËL: One strategy I've seen for that sort of problem, especially when you have a very write-heavy table but that also has a different set of users that needs to read from it, is to set up a read replica. So you have your main that is being written to, and then the read replica is used for reports and people who need to look at the data without being in contention with the table being written. GEOFF: Yeah, Rails multi-DB support now that it's native to the framework is excellent. It's so nice to be able to just drop that in and fire it up and have it work. We used to use a solution that Instacart had built. It was great for our needs, but it wasn't native to the framework. So every single time we upgraded Rails, we had to cross our fingers and hope that it didn't, you know, whatever private APIs of ActiveRecord it was using hadn't broken. So now that that stuff, which I think was open sourced from GitHub's multi-database implementation, so now that that's all native in Rails, it's really, really nice to be able to use that. JOËL: So these kinds of database tricks can help make the application much more performant. You'd mentioned earlier that when you were trying to make your test performant that you had introduced parallelism, and I feel like that's maybe a bit of an intimidating thing for a lot of people. How would you go about converting a test suite that's just vanilla RSpec, single-threaded, and then moving it in a direction of being more parallel? GEOFF: There's a really, really nice tool called Knapsack, which has a free version. But the pro version, I feel like if you're spending any money at all on CI, it's immediately worth the cost. I think it's something like $75 a month for each suite that you run on it. And Knapsack does this dynamic allocation of tests across containers. And it interfaces with several of the popular CI providers so that it looks at environment variables and can tell how many containers you're splitting across. It'll do some things, like if some of your containers start early and some of them start late, it will distribute the work so that they all end at the same time, which is really nice. We've preferred CI providers that charge by the minute. So rather than just paying for a service that we might not be using, we've used services like Semaphore, and right now, we're on Buildkite, which charge by the minute, which means that you can decide to do as much parallelism as you want. You're just paying for the compute time as you run things. JOËL: So that would mean that two minutes of sequential build time costs just the same as splitting it up in parallel and doing two simultaneous minutes of build time. GEOFF: Yeah, that is almost true. There's a little bit of setup time when a container spins up. And that's one of the key things that we optimize. I guess if we ran 200 containers if we were like Shopify or something like that, we could technically make our CI suite finish faster, but it might cost us three times as much. Because if it takes a container 30 seconds to spin up and to get ready, that's 30 seconds of dead time when you're not testing, but you're paying for the compute. So that's one of the key optimizations that we make is figuring out how many containers do we need to finish fast when we're not just blowing time on starting and finishing? JOËL: Right, because there is a startup cost for each container. GEOFF: Yeah, and during the work day when our engineers are working along, we spin up 200 EC2 machines or 150 EC2 machines, and they're there in the fleet, and they're ready to go to run CI jobs for us. But if you don't have enough machines, then you have jobs that sit around waiting to start, that sort of thing. So there's definitely a tension between figuring out how much parallelism you're going to do. But I feel like to start; you could always break your test suite into four pieces or two pieces and just see if you get some benefit to running a smaller number of tests in parallel. JOËL: So, manually splitting up the test suite. GEOFF: No, no, using something like Knapsack Pro where you're feeding it the suite, and then it's dividing up the tests for you. I think manually splitting up the suite is probably not a good practice overall because I'm guessing you'll probably spend more engineering time on fiddling with which tests go where such that it wouldn't be cost-effective. JOËL: So I've spent a lot of time recently working to improve a parallel test suite. And one of the big problems that you have is trying to make sure that all of your parallel surfaces are being used efficiently, so you have to split the work evenly. So if you said you have 70 minutes worth of work, if you give 50 minutes to one worker and 20 minutes to the other, that means that your total test suite is still 50 minutes, and that's not good. So ideally, you split it as evenly as possible. So I think there are three evolutionary steps on the path here. So you start off, and you're going to manually split things out. So you're going to say our biggest chunk of tests by time are the feature specs. We'll make them almost like a separate suite. Then we'll make the models and controllers and views their own thing, and that's roughly half and half, and run those. And maybe you're off by a little bit, but it's still better than putting them all in one. It becomes difficult, though, to balance all of these because then one might get significantly longer than the other then, you have to manually rebalance it. It works okay if you're only splitting it among two workers. But if you're having to split it among 4, 8, 16, and more, it's not manageable to do this, at least not by hand. If you want to get fancy, you can try to automate that process and record a timing file of how long every file takes. And then when you kick off the build process, look at that timing file and say, okay, we have 70 minutes, and then we'll just split the file so that we have roughly 70 divided by number of workers' files or minutes of work in each process. And that's what gems like parallel_tests do. And Knapsack's Classic mode works like this as well. That's decently good. But the problem is you're working off of past information. And so if the test has changed or just if it's highly variable, you might not get a balanced set of workers. And as you mentioned, there's a startup cost, and so not all of your workers boot up at the same time. And so you might still have a very uneven amount of work done by each worker by statically determining the work to be done via a timing file. So the third evolution here is a dynamic or a self-balancing approach where you just put all of the tests or the files in a queue and then just have every worker pull one or two tests when it's ready to work. So that way, if something takes a lot longer than expected, well, it's just not pulling more from the queue. And everybody else still pulls, and they end up all balancing each other out. And then ideally, every worker finishes work at exactly the same time. And that's how you know you got the most value you could out of your parallel processes. GEOFF: Yeah, there's something about watching all the jobs finish in almost exactly, you know, within 10 seconds of each other. It just feels very, very satisfying. I think in addition to getting this dynamic splitting where you're getting either per file or per example split across to get things finishing at the same time, we've really valued getting fast feedback. So I mentioned before that our Jest specs start the moment NPM packages get built. So as soon as there's JavaScripts that can be executed in test, those kick-off. As soon as our gems are ready, the RSpec non-system tests go off, and they start running specs immediately. So we get that really, really fast feedback. Unfortunately, the browser tests take the longest because they have to wait for the most setup. They have the most dependencies. And then they also run the slowest because they run in the browser and everything. But I think when things are really well-oiled, you watch all of those containers end at roughly the same time, and it feels very satisfying. JOËL: So, a few weeks ago, on an episode of The Bike Shed, I talked with Eebs Kobeissi about dependency graphs and how I'm super excited about it. And I think I see a dependency graph in what you're describing here in that some things only depend on the gem file, and so they can start working. But other things also depend on the NPM packages. And so your build pipeline is not one linear process or one linear process that forks into other linear processes; it's actually a dependency graph. GEOFF: That is very true. And the CI tool we used to use called Semaphore actually does a nice job of drawing the dependency graph between all of your steps. Buildkite does not have that, but we do have a bunch of steps that have to wait for other steps to finish. And we do it in our wiki. On our repo, we do have a diagram of how all of this works. We found that one of the things that was most wasteful for us in CI was rebuilding gems, reinstalling NPM packages (We use Yarn but same thing.), and then rebuilding browser assets. So at the very start of every CI run, we build hashes of a bunch of files in the repository. And then, we use those hashes to name Docker images that contain the outputs of those files so that we are able to skip huge parts of our CI suite if things have already happened. So I'll give an example if Ruby gems have not changed, which we would know by the Gemfile.lock not having changed, then we know that we can reuse a previously built gems image that has the gems that just gets melted in, same thing with yarn.lock. If yarn.lock hasn't changed, then we don't have to build NPM packages. We know that that already exists somewhere in our Docker registry. In addition to skipping steps by not redoing work, we also have started to experiment...actually, in response to a comment that Chris Toomey made in a prior Bike Shed episode, we've started to experiment with skipping irrelevant steps. So I'll give an example of this if no Ruby files have changed in our repository, we don't run our RSpec unit tests. We just know that those are valid. There's nothing that needs to be rerun. Similarly, if no JavaScript has changed, we don't run our Jest tests because we assume that everything is good. We don't lint our views with erb-lint if our view files haven't changed. We don't lint our factories if the model or the database hasn't changed. So we've got all these things to skip key types of processing. I always try to err on the side of not having a false pass. So I'm sure we could shave this even tighter and do even less work and sometimes finish the build even faster. But I don't want to ever have a thing where the build passes and we get false confidence. JOËL: Right. Right. So you're using a heuristic that eliminates the really obvious tests that don't need to be run but the ones that maybe are a little bit more borderline, you keep them in. Shaving two seconds is not worth missing a failure. GEOFF: Yeah. And I've read things about big enterprises doing very sophisticated versions of this where they're guessing at which CI specs might be most relevant and things like that. We're nowhere near that level of sophistication right now. But I do think that once you get your test suite parallelized and you're not doing wasted work in the form of rebuilding dependencies or rebuilding assets that don't need to be rebuilt, there is some maybe not low, maybe medium hanging fruit that you can use to get some extra oomph out of your test suite. JOËL: I really like that you brought up this idea of infrastructure and skipping. I think in my own way of thinking about improving test suites, there are three broad categories of approaches you can take. One variable you get to work with is that total number of time single-threaded, so you mentioned 70 minutes. You can make that 70 minutes shorter by avoiding database writes where you don't need them, all the common tricks that we would do to actually change the test themselves. Then we can change...as another variable; we get to work with parallelism, we talked about that. And then finally, there's all that other stuff that's not actually executing RSpec like you said, loading the gems, installing NPM packages, Docker images. All of those, if we can skip work running migrations, setting up a database, if there are situations where we can improve the speed there, that also improves the total time. GEOFF: Yeah, there are so many little things that you can pick at to...like, one of the slowest things for us is Elasticsearch. And so we really try to limit the number of specs that use Elasticsearch if we can. You actually have to opt-in to using Elasticsearch on a spec, or else we silently mock and disable all of the things that happen there. When you're looking at that first variable that you were talking about, just sort of the overall time, beyond using FactoryDoctor and FactoryProf, is there anything else that you've used to just identify the most egregious offenders in a test suite and then figure out if they're worth it? JOËL: One thing you can do is hook into Active Support notification to try to find database writes. And so you can find, oh, here's where all of the...this test is making way too many database writes for some reason, or it's making a lot, maybe I should take a look at it; it's a hotspot. GEOFF: Oh, that's really nice. There's one that I've always found is like a big offender, which is people doing negative expectations in system specs. JOËL: Oh, for their Capybara wait time. GEOFF: Yeah. So there's a really cool gem, and the name of it is eluding me right now. But there's a gem that raises a special exception if Capybara waits the full time for something to happen. So it lets you know that those things exist. And so we've done a lot of like hunting for...Knapsack will report the slowest examples in your test suite. So we've done some stuff to look for the slowest files and then look to see if there are examples of these negative expectations that are waiting 10 seconds or waiting 8 seconds before they fail. JOËL: Right. Some files are slow, but they're slow for a reason. Like, a feature spec is going to be much slower than a model test. But the model tests might be very wasteful and because you have so many of them, if you're doing the same pattern in a bunch of them or if it's a factory that's reused across a lot of them, then a small fix there can have some pretty big ripple effects. GEOFF: Yeah, I think that's true. Have you ever done any evaluation of test suite to see what files or examples you could throw away? JOËL: Not holistically. I think it's more on an ad hoc basis. You find a place, and you're like, oh, these tests we probably don't need them. We can throw them out. I have found dead tests, tests that are not executed but still committed to the repo. GEOFF: [laughs] JOËL: It's just like, hey, I'm going to get a lot of red in my diff today. GEOFF: That always feels good to have that diff-y check-in, and it's 250 lines or 1,000 lines of red and 1 line of green. JOËL: So that's been a pretty good overview of a lot of different areas related to performance and infrastructure around tests. Thank you so much, Geoff, for joining us today on The Bike Shed to talk about your experience at CommonLit doing this. Do you have any final words for our listeners? GEOFF: Yeah. CommonLit is hiring a senior full-stack engineer, so if you'd like to work on Rails and TypeScript in a place with a great test suite and a great team. I've been here for five years, and it's a really, really excellent place to work. And also, it's been really a pleasure to catch up with you again, Joël. JOËL: And, Geoff, where can people find you online? GEOFF: I'm Geoff with a G, G-E-O-F-F Harcourt, @geoffharcourt. And that's my name on Twitter, and it's my name on GitHub, so you can find me there. JOËL: And we'll make sure to include a link to your Twitter profile in the show notes. The show notes for this episode can be found at bikeshed.fm. This show is produced and edited by Mandy Moore. 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. If you have any feedback, you can reach us at @_bikeshed or reach me at @joelquen on Twitter or at hosts@bikeshed.fm via email. Thank you so much for listening to The Bike Shed, and we'll see you next week. Byeeeeeee!!!!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

The Bike Shed
350: 21 Bell Salute

The Bike Shed

Play Episode Listen Later Aug 16, 2022 52:09


It's Steph and Chris' last show. Steph found a game, and if you've been following the journey, all of the Test::Unit test files are now live in RSpec. JWTs really grind Chris' gears. They wrap up with things they've learned, takeaways they've had, and their proudest podcasting moments. They also thank all the folks who've helped make The Bike Shed happen. 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. Microservices (https://www.youtube.com/watch?v=y8OnoxKotPQ) Transcript: CHRIS: One more round of golden roads, our golden. So here we go. STEPH: Oh, one more round of golden roads. Okay, maybe that's going to get to me today. [laughs] CHRIS: [singing] Golden roads take me home to the place. STEPH: [singing] I belong. CHRIS: Yeah, there you go. Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Chris Toomey. STEPH: And I'm Steph Viccari. CHRIS: And together we're here to share a bit of what we've learned along the way, at least one more time. So with that [chuckles] as an intro, Steph, what would you say is new in your world? STEPH: Hey, Chris. Well, today is the big day. It is the day that you and I are recording our final Bike Shed episode, which we have all the feels about, and we will definitely dive into. But to ignore some of that for now, I have another small fun update I can provide about a new game that I found. So one of the things that's new in my world is I started playing a new board game with Tim; it's called Ticket to Ride. Have you heard of that? CHRIS: I have. I don't know if I've played it. I feel like it's a particularly popular one now. But I don't know if I've ever had the pleasure. STEPH: It's a very cute game, so we have the smaller version of it. For anyone that's not familiar, it's essentially a map. And then there's a bunch of spots where you can build trains and connect them, and then you get tickets. So your goal is that you're going to connect one location to another location. And then you get points and yada yada, but it's so much fun and especially the two-player version. It's like this perfect 20, maybe 30-minute game. I'll be honest; I'm not really a board game person. I always enjoy it. Once I get into it, then I'm like, this is great. I don't know why I was resistant to this. But every time someone's like, "Do you want to play a board game?" I'm like, "Not really." [laughs] I first have to get into it. But I have really enjoyed Ticket to Ride. That's been a really fun game to play. And it's been a nice way to, like, even during the day, we'll break for lunch and squeeze in a game. CHRIS: Well, I love good two-player games. They're hard to find. But when you find a good one, and it's got that easy pickup and play...I believe I'm going to now purchase this. And thank you for the tip. STEPH: Yeah, this is definitely one of those where it's easy to pick up, and then you can get the expanded board. So there's a two-player version, but then yeah, you can get one that's a map of the U.S. or a map of Europe. And I think it accommodates up to five players as the maximum, so not a huge group but definitely more than two. On a slightly more technical note, I have something that I'm very excited to share. It is a journey that you have been on with me, that everybody listening has been on this journey with me. And I'm very excited. I see you nodding your head, so I'm guessing that you're going to know where I'm headed with this. But I'm very excited to announce that all of the Test::Unit test files now live in RSpec. So that is a big win. I'm very, very excited for that to be a previous state of life and not an ongoing state of life. Because I have certainly developed too much niche knowledge around migrating these tests, and that became apparent to me when I was pairing with another developer that works with the client because they had offered...they had some time. They're like, "Hey, do you want help migrating a test file?" And I was like, "Sure." I was like, "But this is wonky enough, like, we should pair and work on this together because I just know some ins and outs. And I don't want you to have to learn a lot of the hard lessons that I've learned." And the test that we happened to pick up was very gnarly. It had a lot of mystery guests. And we spent, I think it was a good two hours. And we only migrated one of the tests, so not even a full file but one of the tests. And at the end of it, I was like, I know way too much about some of the oddities and quirkiness of this. And we got through it, but we decided that wasn't a good use of their time for them to go at this alone. So that's why I'm extra excited and relieved because I didn't want this task to carry on to someone else. So, hooray, we did it. CHRIS: Hooray. Just in time. You're Indiana Jones grabbing your hat right as you roll out and off to [laughs] be away from the project for a bit. So you stuck the landing. Well done, Steph. STEPH: Thank you. Thank you. So that's some great news. And then also, everything else in life is pretty much focused around getting ready for maternity leave. That's about to happen soon, and I am so ready. I have thoroughly enjoyed a lot of the things that I'm doing, [laughs] but goodness, being pregnant is hard. And I am very much ready for that leave. So also, a lot of the things that I'm doing right now are very focused on making sure everything's transitioned and communicated and that I just feel really good about that day of departure. That covers all the newness in my world other than the big thing that we're just not talking about yet. How about you? What's new in your world? CHRIS: Well, continuing to skirt the bigger topic that we will certainly get to in the episode, what is new in my world? I'm actually quite excited workwise right now. We have a much larger body of work that finally we got the clarity. All the pieces fell into place, and now we're sort of everybody rowing in the same direction. There's interesting, I think, really impactful code that we're writing for Sagewell right now. So that's really fantastic. We've got the whole team back together on the engineering side. And so we're, I think, in the strongest and most interesting point that I have experienced thus far. So that's all really fantastic. On a slight technical deep dive, you know what really grinds my gears? It's JWTs. JSON Web Tokens and I have never gotten along. It's never been a match made in heaven. And we have a webhook that comes from Plaid. Plaid is a vendor for connecting bank accounts and whatnot. And they have webhooks like many people do. So they can inform us when things change, lovely feature of how we build web apps these days. But often, there's a signature that says, "This is definitively from us, and you can trust us." And usually, it's some calculated signature, HMAC, or something like that. For some reason, Plaid's uses JWTs, and more than that, they use JWKs. So there's JWT which is the signature. That JWT itself is signed with a JWK. You have to fetch the JWK from their server based on the key ID in the header of the JWT. But how do you know if you can trust the JWT before you've gotten the JWK? All of this broke in a recent upgrade. We went from Heroku-20 to Heroku-22 to the new platform with Heroku, which bumped us to OpenSSL 3.0, and it turns out JWT doesn't work with it. And so that's sad. It's a no. It's going to be a no. It turns out the way that OpenSSL 3.0 works is incompatible with some of the code paths in JWT. And so I was like, wait, we just can't do this? And it's low-level cryptographic primitive stuff that I'm not comfortable messing around with. I'm not going to hop in there and roll up my sleeves. And even just getting to the point that I understood what was broken about this took like an hour and a half just to sort of like, wait, which is okay...so the JWT signs and encodes. And this will be a theme that we come back to later, but I think web development should be simpler. I think we should strive for simplicity. And this is a perfect example where I'm guessing Plaid uses JWTs and that approach to communicating security things often, but I've not seen it used much for signing webhooks. And, oof, it led to a complicated day. And it's unfixable now as far as I can tell. There is a commit on the JWT Ruby repo as of five days ago, but it doesn't build in our system. And it's not released. And it's just a mess. So yeah, engineering is complicated. I'm both wildly excited about what we're doing at Sagewell, and then today was this local minimum of like, oh, JWTs again. Again, we find ourselves battling. And you won today, but hopefully not for too long. STEPH: Oof, how did this manifest that you first noticed? So is it because a webhook suddenly stopped working, and that was like the error that rose up, and that's what helped you dive into it? CHRIS: Yeah, we have a little bit of code in the controller for where Plaid events come in. We calculate and verify the signature of the webhook to make sure that it's valid, and we reject it otherwise. And we alert ourselves via Sentry, and then we also have a Datadog scan that can show what's the status code of the response. Because these are incoming HTTP payloads or requests, and so we can see there were 200 up until this magical day when suddenly everything changed. And that was when we switched Heroku stacks. And then we can see it also in Sentry. So we're able to look at it, and we're like, why are none of the Plaid webhooks able to verify the signature anymore? That seems weird. And so then Datadog confirmed that it consistently was broken from this point in time. And then we were able to track that back. It was also pretty easy to guess because the error was "pkeys are immutable in OpenSSL 3.0," and that was the data. And I was like, oh, cool, that sounds fun. Let me go figure out what that means. STEPH: [laughs] Well, it's a nice use of Datadog. I remember in the past you were talking about adding it. And I was excited because I've never been at that point where a team has just introduced it; either a team doesn't have it, and they wish they had more insights, or they have it and don't use it. And nobody ever checks the board. So that's a nice anecdote for Datadog helping you out. Yeah, I'm not envious of your situation, friend. CHRIS: I do love the cup half full take [laughs] that you have on the overall situation, but that's nice how Datadog worked out for you. And you know what? It was. Thank you, Steph, for once again being that voice of positivity. STEPH: I appreciate that you enjoy it because there are times that when someone points it out to me that I do that, I have to be like, "I'm sorry, I'm not trying to be toxic positivity over here. [chuckles] That's just how my brain works." CHRIS: Oh, you are definitively not toxic positivity. That's a different thing. Because you ended with but also, I feel bad for you, and I'm glad that I'm not in your shoes. So you are the right level of positivity. I don't think I could have talked to you for three and a half years as co-host on a podcast if I didn't appreciate the level of positivity or the general approach that you bring to thinking about stuff. STEPH: Okay. Well, to borrow a phrase from Matt Sumner, who has been a guest on the show, cool, cool, cool, cool. I'm glad my positivity has been well calibrated. And I was about to say I'm interested to hear how this turns out for the team. [laughs] But we're in an awkward spot where I mean, you and I, we can still totally chat. But listeners won't get to hear the rest of that particular saga. I mean, you can share. I mean, you do you. I'm setting all sorts of boundaries for you right now. Okay. And now I'm just rambling, and I'm getting weird with it. Because the truth is that, you know, we won't be back. And this is our final episode together. So I think let's just go ahead and rip off the Band-Aid. Let's dive into it. Let's talk about it. Given that it's our last episode that we are recording, we thought of a couple of things that we'd like to talk about. You brought up a great idea that I'm excited to dive into. Do you want to lead us in? CHRIS: Sure. Well, if we go back all the way to Episode 172, that is the first episode that you came on as a guest. I actually continue to really love the title of that episode, which is What I Believe About Software. And it both captured that conversation really well, but also, more generally, it's actually become the tagline of the show when we do our little introduction. What do we believe about building great software? Et cetera. And I think that's been the throughline of the conversations that we've had is what remains true. What are the themes? Not necessarily the specific technologies, although we certainly talk about that. But what do we believe about building great software? And so today, I thought it would be fun for us to talk about what do we still believe about building great software? It's roughly three and a half years or so that we've been doing this. What's still true? STEPH: Oh, well, I have the first unequivocal one, the thing that I still believe about building great software, and that's you should hire thoughtbot. That's definitely the way to go. We'll help you get it done, not that I'm biased in any way. CHRIS: No. I'd say collectively between us; there's zero bias with regard to thoughtbot or any other web development shop out there. But thoughtbot is the best. STEPH: All right, perfect. So we've got the first one, the clutch one of hire thoughtbot. And then I also really like this topic. And I still think back to that first episode that I recorded with you and how much fun that was and how that really got me to start thinking about this. Because it was something that, at the time, I didn't really reflect on a lot in terms of what does it take to build great software? I was often just doing the day-to-day actions but then not really going high-level think about it. So I'm excited this is one of the topics that we're revisiting. So for the next one, this one is, I don't know, maybe it's a little cutesy, but I was trying to think of an alliteration that I enjoyed. And so this one is be an assumption assassin. So what assumptions are you making? And then how can you validate or disprove them? And that is something that I find myself doing constantly. And it always yields better work, better questions, better software, better code, better code reviews. And that's my first one is be an assumption assassin and identify what assumptions you have. And I had a really good example come up today while I was having a conversation with Joël about something that I was looking to merge. But I was a little hesitant about it because there are some oddities that I won't dig in too deeply. But essentially, there's a test that I migrated that highlights an existing concern in the code. And I was like, should I go ahead and merge this test that documents it, or should I wait to fix that concern and address it? And he brought up a good point. And he's like, "Well, we're assuming it's a bug and an issue, but it may not actually be depending on how the software is being used." And so then he was encouraging me to reevaluate that assumption that I had where I'm like, oh, this is definitely a problem to, like, I don't know, is it a problem? Let's ask somebody. CHRIS: First off, I love that as a theme, as one of the things that you still believe about software. Second, I believe you correctly said that you were looking for an alliteration, but my brain heard acronym. STEPH: [laughs] CHRIS: And so then I was like, B-A-A-A. Is it BAAA? What are you going for there? Oh, you just wanted a bunch of As. Okay, I got it now. Secondly or thirdly, I think I'm on my third now. Apparently, within Sagewell team culture, one of the things that I'm most known for is... there are two phrases: one is just to name it, and the other is to be clear. And these are the two things that I do apparently constantly so much that it's become a meme within the team. It's just like, okay, everybody's been talking. But I just want to make sure we're on the same page here. So just to be clear, or just to name it, here's what I'm seeing. But I agree; I think taking those things...what are the implicit bits? What are the assumptions? And making them more explicit. Our job as developers is just to yell at computers all the time and make them try and do human stuff. And there's so much room for lossy conversions at every point in that conversation chain. And so yeah, being very clear, getting rid of assumptions, love it. It's all great stuff. Actually, in a very related note, the first on my list is that code is for humans to read. This is one of the things that I believe most deeply and most impacts the way that I write software. Any given piece of functionality that we want to author in our code feels like 10, 20, 50, frankly, almost infinite different versions of the code that would produce nearly identical functionality. So at the end of the day, the actual symbols and strings of text that we bring together to write the code is all about other humans, other people on your team, you five months from now, you a week from now, frankly, or me. I'm going to say me, me a week from now. I want to do future me and everyone else on the team a solid and spend that extra 10% of okay, I have something that works now, but let me try and push it around and try and massage it into a shape that is a little more representative of how we're actually thinking about the code, how we talk about it as an organization. Is that the word that we use to describe that domain concept? Maybe we could change that just a little bit. Can I push more of this into the private API? What actually needs to be known here? And I think that's where I'm happiest is in those moments because that's where all of the parts of the job come together, the bit where I trick a computer into doing what I want and simultaneously making it so that that code is revisitable, clear, expressive, all of those things. So yeah, code is for humans. And that's true across every language, and framework, and domain that I have worked in. And I've only believed it more and more so over time. So yeah, that's mine. STEPH: Yeah, I love that one. That's one of the things that comes to mind when people talk about disliking code reviews. And I can imagine there are a number of reasons that people may have had a poor experience with a code review process. But at the end of the day, if you're not getting that feedback or validation from fellow humans, then how do you know that you've been successful, that you've written something that other people can follow up on? Which goes back to the assumptions in terms of like, you're assuming that you have written something that your future self or that other people are going to be able to read and maintain down the road. So yeah, I love that one. One of the other things that I still hold really true to building great software is prioritize early and often. So always be checking in to understand with your users, with your tech concerns, with data that you may have, new insights, and then just confirm that yes, you and the team are constantly working on the thing that has been prioritized and that is the most important. And also, be ready to let go. That can be really hard. I have definitely had those moments in my career where I've spent two weeks working really hard on something. And then we've realized that the thing that we were pursuing isn't that valuable, or it's something that users don't need or actually want. And so it was better to let go of it than to pursue it and ship it anyways. So that's one of my other mantras that I have adopted now is prioritize, prioritize, prioritize. CHRIS: Unsurprisingly, I agree wholeheartedly with all of that. We're still searching for that thing, that core thing that we disagree on other than Pop-Tarts and IPAs. But I don't know that today is the episode that we're actually going to find that. But yeah, prioritizing is such a critical activity. And it is this interesting collaboration point. It gets different groups together. It's this trade-off. It's this balance. And it's a way to focus on and make explicit the choices that we're making. And we're always making choices. We're always making trade-offs. And so being more explicit, being more connected and collaborative around those I believe in so, so, so much. So love that that was something on your list. Let's see, next up on my list is reduce complexity, just sort of as an adage, just always be reducing complexity. It is amazing to me in my time, particularly as a consultant, but even now, this is something that I hold very true is just it's so easy to grow a system in anticipation of future complexity or imagine that the performance concerns that we're going to run into will be so large that we must switch from Postgres and a nice, simple atomic database into a sharded, clustered Kafka queue adventure. And there are absolutely cases that make sense for that sort of thing. But at a minimum, I beg of you, anyone starting a new system, don't start with microservices. Don't start with an event queue-based system. These are wildly complex versions of what often can be done with so much simpler of an application. And this scales through to everything. What's the complexity of an API? Do we need caching in that API layer? Or can we just be a little bit inefficient for a little while and avoid the complexity and the overhead of caching? Turns out caching is a tricky thing to get right, just as an aside. And so the idea of like, oh, let's just sprinkle in a little bit of caching. It'll be easy, and then we'll get better performance, like, yeah, but did you get it right? Or did you introduce a subtle bug into your program that's going to be really hard to debug later? Because do you cache in development? Well, maybe, I'm not sure, could be. So over time, this is something that I've sort of always felt, but I've only ratcheted it up. It's only something that I've come to believe in more and to hold more firmly to. I think earlier in my career, it was something that I felt, but I would more easily be swayed by aspirational ideas of the staggering amounts of traffic that we would be getting soon or the nine different ways that the data model will expand. And so, we should code the current version in anticipation of that. And I have become somewhat the old man on his lawn yelling at the clouds like, "Nah, we don't need it yet. We can grow to that." And there's a certain category of things that are useful to try and get out in front of and don't introduce additional complexity, but they're a tiny, tiny list. And so, for most things, my stance is what's the simplest thing that we can get away with right now, that still provides a meaningful experience to our users, that doesn't compromise on security or robustness or correctness but just solves the problem we have right now? And over and over and over again, that has served me incredibly well. So yeah, keep that complexity at bay. STEPH: That is one that I've definitely struggled with. And frankly, it works in my favor, that idea of keeping things simple. Because I'm terrible when it comes to predicting the future or trying to build things in a way that I just don't have enough information to really drive the architecture or the application that I'm building. So anytime I'm trying to then stretch and reach for the future in those ways unless I really have a concrete understanding of I am building for these particular scenarios, it's really hard to do. So I very much like keeping it simple and not optimizing before you need to. And it reminds me of I think it's Mark Twain, who has a quote, "Worrying is like paying a debt that you don't owe." And that's something that comes to mind for me when also writing code and building features and software is that I tend to be someone who will worry about stuff. And I'm like, oh, is this going to be easy to extend? Is it going to be what it needs to be six months from now if we need to add more features to this and build on top of it? And I have to remind myself it's like, well, let's just wait. Let's wait till we get there and we know more. One of my other ideas that couples nicely with the one that you just shared in regards to keeping things simple and then waiting for those needs to arise is that mistakes are going to happen. They are a part of the process. As we are learning and growing and we're stretching our skills and trying things out, things are going to go wrong. We're going to introduce bugs. And to take those opportunities, that's when we start to use that feedback to then improve things like observability, like capturing logs, and how we handle error reporting or having a plan for emergencies. So maybe that's the part of worrying that can pay off is thinking through, all right, if something does break, or if something gets shipped that shouldn't, then what is our plan in how we handle that? How do we roll back? Or how do we get things back to a stable build? CHRIS: It's funny. I was actually visiting with a friend this past weekend, and we were chatting more generally about life things but the idea of worrying and anticipation and trying to prepare for every bad outcome. And there's the adage of an ounce of prevention is worth a pound of cure. But increasingly, both in life, depending on the context, and in code, I've found that I've shifted to the opposite of it's impossible to stop everything. There are going to be bugs that are going to get out there. There are going to be places where we code things incorrectly. And I would rather...I still want to try as hard as I can to get things right, to be clear. I'm not giving up on trying. But I'm all the more focused on how do we know and how do we recover when those things happen? So it's interesting that you just described exactly that, which, again, is a very human life conversation, and yet it applies to the code. STEPH: I love that rephrasing of it. Instead of the mistakes are going to happen, it's, like, how do we know, and how do we recover? I think that's perfect. I've also found that by answering the how do we know and how do we recover, that really helps you build trust with clients as well. Because again, things are going to happen, things are going to break. And the more prepared you are for that and then the better plan that you have, and then they can watch how you execute that plan, and it's going to establish a lot of deep trust with other engineers and also the team that you're working with, that you have been thoughtful and that you have ideas on how are we going to address this? Instead of waiting for that moment to happen. That's going to happen too. You're going to make decisions in the heat of the moment. But I have found that to be a really useful way to establish yourself with a team in terms of I care about this team and these processes and this application. So how do we handle the bad times, not just the good times? I do want to circle back because you alluded to the fact that you and I, we've tried to find things that we disagree on. And so far, Pop-Tarts and beer have been the two things that we disagree on. But I do have a question for you that maybe I will disagree with you on. But I need to know some more about it first. You have alluded to there's the Brussels snack, (Oh, I'm going to get this wrong.) Brussels sprout snack hour or working lunch, something combination of those words. [laughs] And it's the working lunch that has stuck out to me, and I've wanted to ask you about it. So here I am. I'm asking you about it. What's a working lunch? What's the Brussels snack happy hour, snackariffic working lunch look like? CHRIS: This is fantastic. I love that you waited until the last episode that this was rolling around in the back of your head. And you're like, are you making the team work through lunch? And now, on this final episode, we get to address the controversy that has been brewing in the back of your head. Spoiler alert, no, this is just ridiculous nomenclature. These are two meetings that we have that are more like, let's get the dev team together and talk about stuff that's in our platform sort of developer experience. Or stuff in observability often is talked about in this context because it doesn't quite impact users, but it's how we think about the work. And so there are two different meetings that alternate every other week. So every Friday afternoon, we do this, but it's one of two meetings depending on the day. So there's a crispy Brussels snack hour that was the first one that was named, which was named purely for nonsense reasons because we don't have anything else that's named nonsensically in our organization. And so I was like, oh when we name this meeting, we should make it nonsense because we don't have any other...We don't have, you know, an SOA microservices fleet with Barbie doll and Galactus and all of the other wonderful names. Those are references to the greatest video ever about microservices; if you've not seen it, that will be in the show notes. It's required reading. But anyway, we don't have that. And so we thought, let's be funny with the name of this. So the crispy Brussels snack hour is one, and the crispy Brussels we wanted something that was...the first one is a planning meeting. The second is like, let's actually sort of ensemble program. Let's get the four of us together, and we'll work on some of the stuff that we're talking about here but as a group. And so I wanted the idea of we're working, and so I was like, oh, this will be the crispy Brussels work lunch. But it's purely a name. It's the same time slot. It's 3:00 o'clock on a Friday afternoon. [laughs] So it is not at all us working through lunch. I don't think we should work through lunch. I'm concerned that you thought that for a while, and you were just like, I'm a little worried, but I'm not going to bring it up. But I'm glad we got to cover this before we wrapped up this whole Bike Shed co-hosting adventure together. STEPH: I feel relieved and also a little robbed of an opportunity for us to have something that we disagree on because I thought this might be a thing. [laughs] CHRIS: We can continue searching for that thing. But maybe it's okay that we agreed on most stuff for the run [laughs] of this fun, little show that we did together. STEPH: Yeah, that's gone on quite a time. We've got like three years together that we have managed to really only find two, I mean, very important of course, two things. But yeah, it's been pretty limited to those two areas. And each time that you'd mentioned the work lunch, I was like, huh, I need to ask about that because I have feelings about it. But then, you always would dive into very interesting stories of things that came out of it, and I quickly forgot about it. So this feels good. This feels like very good important closure. I'm glad that this finally surfaced. But circling back, since I took us on a detour for a little bit, what are some other things that you still hold deeply about building great software? CHRIS: I've really got one last thing on the list. It's interesting, there's not a ton technically in this list, which I think represents broadly how I feel about software, and I think how you feel about software. It's like, it's actually mostly about how the people interact at the end of the day. And you can program in any language or framework, and you can get the job done. We certainly have our preferences and things that we enjoy. But the last one really rounds us out, which is think about the users. I always want to be anchoring the conversations that we're having, the approach that we're taking to building the software in what do the users think? Who are our users? What do we know about them? What do they care about? How are they using this technology? How is it impacting their lives? We've talked a number of times about potentially actually watching the sales demo as an engineering team, trying to understand what's the messaging that we're putting out into the world for this piece of software that we're building? Or write along with customer support and understand what are the pain points that people are hitting? And really, like, real humans, what are they experiencing? Potentially with a name attached. And that just changes the way that you think about the software. There's also even the lower-level version of it. As we're building classes or modules, what are the public facets of that, and what are the private API? What's the stuff that we're hiding away? And what's the shape that we are exposing to the outside world for varying definitions of outside? And how can we just bring in a little bit of empathy to try and think about, again, in the case of like the API for a class, it's probably you on the other side of it, but it's future you in a slightly different mindset with a little bit less information and context on the current problem that you're working on. And so, how can we make things easier for ourselves in the code, for our users at the end of the day? How can we deliver real value that is not mired in the minutiae of technical complexity and whatnot but really is trying to help people live better lives? That's a little too fancy as I say it out loud. But it is kind of the core of what I believe, so I'm not going to take it back. STEPH: I love how you've expanded users where more traditionally, it's people that are then using the software. But then you've expanded it to include developers because that is something that is often on my mind and something that I just agree with wholeheartedly in terms of when you're writing software; as you mentioned before, software is for people. And so we want to include others. And it does improve people's lives. People show up to work every day, and if you've been thoughtful if your past you has been thoughtful, it's either going to give you your future self a better day, or it's going to give other people a better day. So I think that's a very fair statement, improving lives by being thoughtful in regards to focusing on the users, people consuming software, and working in the codebase. CHRIS: I know we've talked about this before, but I was having a conversation with one of the developers on the team at Sagewell just last week, and they were mentioning how they really loved working on admin features. And I was like, oh, that's interesting. Let's talk more about that. And it was really it's that same thing that I think you and I have discussed of like there's that immediacy. There's that connection. These are actually colleagues, but you can build software to make their day better. You can understand in detail what the pain points are. What's the workflow that as you watch it, you're like, oh, I could put a button up in the corner of the screen that would automate almost all of this and your day would be that much faster? Oh, let me do that. That's exciting. And so I love that as another variation of it, like, yeah, there's for other developers. There's also for the admin team or other users in the organization of the software. There are so many different versions of users, but I think I think we build a better thing if we think about them more. STEPH: I have definitely worked with teams where I can tell that certain people are demoralized, and it comes down to they feel frustrated and often disconnected from the people that they are building for. And so then you really feel isolated. I'm pushing code around, but I don't really see the benefit or the purpose of it. And I think that's very hard for developers who typically want to build something that's going to be useful and not feel like it's just going to be thrown away. So connecting your team to those users, I certainly understand. Getting to build something for your colleagues and then they get to say how much they like it is an incredible, rewarding experience. You also touched on something that I really appreciate, where you highlighted that a lot of the technical decisions that we make are important, but they're not at the center of the things that we believe when it comes to building great software. And that's something that I will often reflect on. Like, as we were thinking through these particular ideas that we still hold true today, how mine are more people and process-focused and rarely deep in the technical weeds. And there are times that I think, well, shouldn't there be something that's more technical, something that's very concrete? Yes, you should build your code this way or build your application or use a specific technology. But after all the projects and teams that I've been a part of, that's just usually not the most important part. And so I appreciate that you highlighted that because sometimes I have to remind myself that, yes, those things can be challenging, but it's often with people and process. That's where the heart of great software lies. CHRIS: That's a fantastic phrase, I think, that really encapsulates all of the conversations that we're having here. 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 you cut your debugging time in half. So why do developers love Airbrake? Well, 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 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 enables 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 and includes 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. So head on over to airbrake.io/try/bikeshed to create your FREE developer account today! CHRIS: Actually shifting gears a little bit, so we've just talked about what we still believe about building great software. I'm intrigued. We've been chatting for a number of years here on this microphone, these microphones. We have separate ones because we're in different states. But I'm interested; what have we changed our minds about? What have you changed your mind about, Steph? I got a couple of ideas, but I'm intrigued to hear yours. STEPH: Nothing. I've never been wrong. I've stuck to everything that I've ever thought. CHRIS: That must be boring. STEPH: [laughs] Yeah, that's totally not true there. There are definitely things that I've changed my mind about. One of the things that I've changed my mind about is that people who know the most will ask the fewest questions. That's something that I used to consider the trademark of someone who is a more experienced senior developer in terms of you really know what you're doing. And so you typically don't ask for help or need help very often. And so, I'm going way back in terms of things that I have changed my mind about. But I have definitely changed my mind where people who know the most are actually the ones that do a really great job of constantly asking questions and asking for feedback. And I think that is still a misconception that people still carry forward. The idea that if you're asking a lot of questions or asking for help that you are not as skilled in your work, and I view it as quite the opposite, that you are very good at what you do and that you know precisely the value of your time. And then also reaching out to others for help, and then also just getting validation on things that you may have concerns around. So that's one I've changed my mind on is that I think the more experienced you are, the more questions you tend to ask. CHRIS: Oh, I love that one. It's a behavior that I know...I think we've talked about this before. But as consultants, we try and model it just the like; it's totally fine to ask questions. And because we often come in with less context, it makes sense for us to be asking questions, but I will definitely intentionally lean into it in those contexts to be like, everybody keeps throwing around this acronym. I don't actually know what that is. Let me raise my hand. And my favorite moment is when people disagree on what the acronym or what the particular word or what the particular project is. Like, I ask the question, and people are like, "Oh, it's this," and someone across the room is like, "Wait, that's what it means? I thought it was this totally other thing." I'm like, cool, glad that we sorted that out. Glad that we got that one up in the air. But I actually remember many, many, many years ago, at this point, there was a video series of...PeepCode was the company, and there was the Play by Play series. And so there were particular prominent developers, particularly in the Ruby community. And they would come and sort of be interviewed and pair program. And it was amazing getting to watch these big names that you had heard of, like Yehuda Katz is the one that stands out in my mind. He was one of the authors of merb, which was a framework that was merged with Rails, I want to say around the 3.0 time. And just an absolute, very big name in this world and someone that I looked up to and respected. And watching this video, they had to Google for particular API signatures and Rails methods. They were like, "Oh, how does that work? Is it link to and then you pass the name?" I forget what it was specifically. But it was just this very human normalizing moment of this person who has demonstrably done incredible work in our community and produced very complex software still needs to Google for the order of arguments to a particular method within Rails. I was like, oh, okay, that's good to know. And with complete humility in the moment, I was just like, yeah, this is normal. Like, it's impossible to hold all of that in your head. And seeing that early on shook me off the idea that that's the thing to do is just memorize everything. It's like no, no, get good at asking the questions. Get good at debugging. Get good, yeah, asking questions. It's a core skill rather than a thing that you grow out of. But I definitely shared early on I was like, not allowed to ask questions, that'll be scary. STEPH: I love that example. Because counterintuitively, to me, it demonstrates confidence when someone can say, "Oh, I don't remember how this works," or "Let me go look it up." And so I just very much appreciate when I see someone demonstrating that level of confidence of let's keep going. Let's keep making progress. I'm going to ask for help because that is totally fine, and we are in a safe space. Or I'm going to create a safe space for us to do that. One of my favorite versions of this where you shared like if you ask about an acronym and then people disagree, one of my favorite versions is to ask about a particular area of the codebase and be like, what would you say this code is doing here? What do you think users do here? Like, what is the purpose? What's the point of this? [chuckles] And then having people be able to say, "Oh, yeah, this definitively does this thing." Or people are like, "You know, I'm not sure. I don't even know if that code is getting run." That's one of my favorite outcomes of asking questions. How about you? What's something you've changed your mind about? CHRIS: I made a list of a couple of things like remote is on there. I didn't know if I'd like remote. I wanted to try it for a while. Tried it, turns out I like it a lot. It's complex. You got to manage it, whatever. But that I think everybody's talked about that a bunch. I think probably the most interesting one is deadlines. Initially, in my career, I didn't really feel anything about them. And then I experienced the badness of deadlines. Deadlines are bad. Deadlines are things that come down from on high and then you fail to hit them, and then you're sad. And maybe along the way, you're very stressed and work long hours to try and get there. But they're perhaps arbitrary. And what do they even mean? And also, we have this fixed scope, and they're just bad. And then there was a period of my time where, like, deadlines are bad. The only thing that we do is we show up, and we make the software as quickly as we can. But in reality, there are times that we need that constraint. And in fact, I have found a ton of value in deadlines when used intentionally. So we can draw a line in the sand, and we can say, at this point in time, we will have a version of the software. We have a marketing campaign that we need to align with this. So we got to have something at that point. And critically, if you're going to have a deadline, you've now fixed a point in time. You need to flex other things. And critically, I think the thing to flex is the scope. So we need to have team management. We have user accounts right now, but now we need to organize them into teams. That is like a category of functionality. It's not a singular feature. And so yeah, we can ship teams in the next quarter. What exactly that means is up in the air. And as long as we're able to have conversations essentially on a day-to-day at least weekly cadence as to what will make it in by that deadline and what won't, and we're able to have sometimes the hardest conversations but the very necessary conversations of the trade-offs that we have to make as we're building that software, then I find deadlines are absolutely fantastic tools for focusing and for actually reducing scope but in a really useful way. And getting something out there in the hands of users so that you start to get real feedback so that you start to learn, is this useful? What are the ways that people are using this? What should we lean into and do more of? What maybe should we roll back, actually? So yeah, deadlines. First, I didn't know them, then I feared them. Now I love them but only under the right circumstances. It's a double-edged sword, definitely. STEPH: I, too, have felt the terribleness of deadlines and railed against them pretty hard because I had gone through a negative experience with them but have also shifted my feelings about them where they can be incredibly useful. So I really liked that's one of the things that you've changed your mind about. It also reminds me of one of the other things...I'm going to circle back for a moment to one of the things that I believe about creating great software is to not wait for perfection, and deadlines are a really good tool that helps you not wait for perfection. Because I have also seen teams really struggle or sometimes fail because they waited until there was something perfect to present, and then you realize that you've built the wrong thing. So I do want to transition and talk a bit about the show because it's our last episode, and we should talk about it, and the fun adventures that we've had and some of the things that we've learned or things that we're feeling in the moment. So given that it's been a wonderful three years for me, it's been four years for you since you've been a host on the show. How are you feeling? CHRIS: I'm feeling a bunch of different things sort of all at once. I am definitely going to miss this immensely. Particularly, I loved when I started, and I got to interview a bunch of thoughtboters and other people from the community. But frankly, three-plus years of getting to chat with you has been just such a delight. There's been an ease to it. We kind of just show up and talk about what we're doing. And yet there are these themes that have run through it. And it has definitely helped me hone and shape my thinking and my ability to communicate about what I'm thinking. I've learned that you have a literal superpower to remember the last thing that you were talking about. Listeners, you may not know this, but we are not quite the put-together folks that we may sound like in these recordings. We have a wonderful editor, Mandy Moore, who makes us sound so much better than we are. But we'll often pause and stop and then discuss what we want to talk about next. And Steph always knows the exact phrase that she or I left off on. And it has been so valuable to the team. But really, it's been just such a pleasure getting to have these conversations. It's also been something that has just gently been in the back of my mind at all times. And so, I'm observing the work in any given week as I'm doing it. It's almost like meditation in a certain way, whereas I'm working on something, like, oh, this is actually really cool. I want to take a note about this and talk about it on The Bike Shed with Steph. And having this outlet, having this platform to be able to have those conversations and knowing that there are people out there is fantastic, although it's very weird because really, every one of these recordings is just you and I on a video call. And so there is an audience, I'm pretty sure. I think people listen to the show; I don't know, occasionally they write in, so it seems like they do. But at the end of the day, this really just feels like a conversation with a friend, and that has been so valuable to have. And yeah, I'm definitely going to miss that. It's been a wonderful run, you know, four years is a long time. It's about as long as I've done most things in my career. And so I'm very happy with what we have done here. And there's a trite saying that isn't...yeah, whatever; I'll just say it, which is, "Don't be sad that it's over. Be glad that it happened." And I guess I'm still going to be sad that it's over. But I am so glad that I got the opportunity to do this, that you joined in this adventure and that we got to chat each week. It's been really delightful. STEPH: I really liked how you refer to this as being a meditative state. And that is something that I have certainly picked up from you and thoroughly enjoyed that I have this space that I get to show up and bring these ideas and topics and then get to talk them out with you. And that has been such a nice way to either end the week or start a week. I mean, it doesn't matter. Anytime that we record, it's this very nice moment of the week where we get to come together and talk through some of the difficulties and share our stories. And that's been one of my favorite moments is because you and I get to show up and share everything that's going on. But then when someone writes into the show or if they send a tweet or something and they share their story or their version of something that happened, or if they said that we made them laugh, that was one of my favorite accomplishments is the idea that something that we have done was silly enough or fun enough that it has brought them joy and made them laugh. So I, too, I'm very, very much going to miss this. It has been a wonderful adventure. And I thank you for encouraging me to come on this adventure because I was quite nervous in the beginning. And this has definitely been an aspect of my life that started out as something that was very challenging and stretching my limits, and now it has become this very fun aspect and something that I get to show up and do and then get to share with everyone. And I do feel very proud of it, very much in part to Thom Obarski, who was our initial producer and helped us have that safe space to chat about things. And now Mandy, who keeps the show running smoothly and helps us sound our best week to week. So it's been a wonderful adventure. This is going to be hard to let go. And I think it's going to hit me most. Like, this was one of those things as we're talking about it, it's, like, I'll see you next week. This will be fine. But I think it's going to hit me when there's something that I want to talk about where I'm like, oh, this would be great to talk about, and I'll add it to The Bike Shed Trello board. And I'll be like, oh yeah, that's not a thing anymore, at least not quite in the same way that it was. CHRIS: So what I'm taking away from this is that you're immediately going to delete my phone number the minute we hang up this call and stop recording. [laughs] STEPH: Oh yeah. I preemptively deleted. So that's already done. Friendship is over at this point. CHRIS: That's smart. Yeah, because you might forget otherwise in the heat of the moment as we're wrapping this whole thing up. STEPH: [laughs] CHRIS: But actually, on that note, in a slightly more serious vein, again, there's this weird aspect where the audience is out there. But we're very sort of disconnected, particularly at the moment in time where we're recording. But it has been so wonderful getting various notes from listeners, listener questions, but also just commentary and the occasional thanks and focusing; oh, you pointed me in the direction, or you helped me think through a complicated piece of work or process a problem that we were having. And so that has been just so, so rewarding. And one of the facets of this that has been so interesting to me is being able to connect to people and basically put out there what we believe about software, and for the folks that resonate with it and be able to have that connection instantly. And meeting people, and they're like, "Oh, I've listened to The Bike Shed. I like all these things." I'm like, oh, cool, we get to skip way further into the conversation because I've already said a bunch, and you say you like that thing. So, cool, we're halfway through our introductory chat. And I know that we agree about a bunch of things, and that's really wonderful. And frankly, I'm going to miss that immensely. So for anyone out there who's found something valuable in this, who's enjoyed listening week to week, or perhaps even back to Upcase for things, I would love to hear from you. I'd love to connect to folks. Send me an email, Twitter. I'm on all the places. I'm Chris Toomey in various spots or ctoomey.com on the internet. Chris Toomey on GitHub. I'm findable, I think. Chris Toomey developer will probably get you there. But I would really love to hear from folks, to connect to folks, you know, someday down the road; I think I'll be hiring again. And that'll be fun. I would love to work with some of the folks that have listened to this show or meet you at a conference, or if I happen to be traveling to a city or you're traveling to Boston. Really for me, so much of what this show is about is connecting with people around how we think about building great software. And so, I would love to continue that forward into the future. So yeah, say hi, if you're interested. STEPH: I agree. That's been one of the most fun aspects of being co-host of the show. And I'll be honest, you are welcome to contact me, but I am going to be off-grid for probably six months. [laughs] So just know that there will be a bit of a delay before you hear back from me. But I would definitely love to hear from you. I also want to say a very heartfelt thanks to a couple of people, just folks that have made this journey incredible and have made it so much fun. One, in particular, is everyone at thoughtbot for their continuous stream of knowledge. I mean, frankly, my software opinions wouldn't be half as interesting if it wasn't for everyone at thoughtbot constantly sharing their knowledge and being a source of inspiration. So I deeply appreciate everyone that has contributed to topics and ideas and just constantly churning out blog posts because those are phenomenal. And I also want to give a shout-out to my husband, Tim, because he has listened to The Bike Shed for many years and even helped out with a number of show notes when that was something that you and I used to do before Mandy made our life so much easier and took that over for us. And has intervened a number of times when Utah mid-recording would decide it's time to play. So I want to give a very special thank you to him because he has been a very big supporter of the show and frankly helped me manage through a lot of the recordings for when I had an 80-pound dog that was demanding my attention. CHRIS: I think continuing on the note of thanks; similarly, I'm so grateful to thoughtbot as an organization for everything that is represented in my career. It's a decade-plus that I have been following and then listening to the podcasts and then joining the organization, and then getting so many wonderful opportunities to learn about this thing called web development. And then, even after I left the organization, I was able to stay on here on The Bike Shed and hang out and still chat with you, Steph, which has been really wonderful. So thank you, thoughtbot, so much. Thank you to Joël Quenneville, who will be the continuing host of the show. This show is not going anywhere. And, Steph, you and I aren't really going anywhere, but we won't be around anymore. But we are leaving it in the very, very capable hands of Joël, and I'm super excited to hear the direction that he takes it and Joel's incredibly thoughtful and nuanced approach to thinking about programming and communicating. So I think that will be really wonderful. And lastly, I definitely want to thank Derek Prior and Sage Griffin, the two original hosts of this show, who really produced something wonderful, and for many years, I think it was about four years that they hosted together. I was an avid listener despite actually working at the company the whole time and really loved the thing that they produced and was so grateful that they entrusted me with continuing it forward. And hopefully myself and then with the help of you along the way, we've...I think we've done an okay job, but now it is time to pass the torch or the green lantern. That's the adage I've been going with. Gotta pass the lantern, pass the mantle on to the next one. So, Joël, it's going to be in your hands now. STEPH: Yeah, I'm so looking forward to future episodes with Joël Quenneville. They are going to be fabulous. So I've been thinking in terms of this being our finale episode and then a fun ending for it, so there's a thing called the 21-gun salute, which is the military honor that's performed by firing cannons or artillery. Not to be confused with the three-volley salute, which I definitely confused earlier that is reserved and used at funerals, which this is not. So using the 21-gun salute, I was like, hmm, it is The Bike Shed, and we have this cute ring ring that goes. So I think for our finale, we should have a 21-bell salute as we exit the shed and right off into the sunset. CHRIS: I love it. I couldn't imagine a more perfect send-off. So with that, what do you think? Should we wrap up? STEPH: Yes, but I have one more silly thing to add. I've thought of a new software idiom that I'm excited about. And so, this may be my final send-off into glory that I'd like to share with you. And I think that we should make like a shard and split. CHRIS: [laughs] I so appreciate that in this moment, this final moment that we have together, you choose to go with a punny joke. It is so on brand for the show. It is absolutely perfect. And I think with that note, shall we wrap up? STEPH: Let's wrap up. CHRIS: The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeeeee!!!!!!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

The Bike Shed
347: Tracking Velocity

The Bike Shed

Play Episode Listen Later Jul 26, 2022 38:50


Chris talks about a small toy app he maintains on the side and working with a project called capybara_table. Steph is getting ready for maternity leave and wonders how you track velocity and know if you're working quickly enough? They answer a listener's question about where to get started testing a legacy app. 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. jnicklas/capybara_table: (https://github.com/jnicklas/capybara_table) Capybara selectors and matchers for working with HTML tables Become a Sponsor (https://thoughtbot.com/sponsorship) of The Bike Shed! Transcript: CHRIS: Just gotta hold on. Fly this thing straight to the crash site. STEPH: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Chris Toomey. CHRIS: And I'm Steph Viccari. STEPH: And together, we're here to share a bit of what we've learned along the way. I love that you rolled with that. [laughs] CHRIS: No, actually, it was the only thing I could do. I [laughs] was frozen into action is a weird way to describe it, but there we are. STEPH: I mentioned to you a while back that I've always wanted to do that. Today was the day. It happened. CHRIS: Today was the day. It wasn't even that long ago that you told me. I feel like you could have waited another week or two. I feel like maybe I was too prepared. But yeah, for anyone listening, you may be surprised to find out that I am not, in fact, Steph Viccari. STEPH: And they'll be surprised to find out that I actually am Chris Toomey. This is just a solo monologue. And you've done a great job of two voices [laughs] this whole time and been tricking everybody. CHRIS: It has been a struggle. But I'm glad to now get the proper recognition for the fact that I have actually [laughs] been both sides of this thing the whole time. STEPH: It's been a very impressive talent in how you've run both sides of the conversation. Well, on that note, [laughs] switching gears just a bit, what's new in your world? CHRIS: What's new in my world? Answering now as Chris Toomey. Let's see; I got two small updates, one a very positive update, one a less positive update. As is the correct order, I'm going to lead with the less positive thing. So I have a small toy app that I maintain on the side. I used to have a bunch of these little purpose-built singular apps, typically Rails app sort of things where I would play with a new technology, but it was some sort of like, oh, it's a tracker. It's a counter. We talked about breakable toys in the past. These were those, for me, serve different purposes, productivity things, or whatever. But at some point, I was like, this is too much work, so I consolidated them all. And I kept like, there was a handful of features that I liked, smashed them all together into one Rails app that I maintain. And that's just like my Rails app. It turns out it's useful to be able to program the internet. So I was like, cool, I'll do that for myself. I have this little app that I maintain. It's got like a journal in it and other things. I think I've talked about the journal in the past. But I don't actually take that good care of it. I haven't added any features in a while. It mostly just does what it's supposed to, but it had...entropy had gotten the better of it. And so, I had a very small feature that I wanted to add. It was actually just a Rake task that should run in the background on a schedule. And if something is out of order, then it should send me an email. Basically, just an update of like, you need to do something. It seemed like such a simple task. And then, oh goodness, the failure modes that I fell into. First, I was on Heroku-18. Heroku is currently on their Heroku-22 stack. 18 being the year, so it was like 2018, and then there's a 2020 stack, and then the 2022. That's the current one. So I was two stacks behind, and they were yelling at me about that. So I was like, okay, but whatever. Can I ignore that for a little while? Turns out no, because I couldn't even get the app to boot locally, something about some gems or some I think Webpacker was broken locally. So I was trying to fix things, finally got that to work. But then I couldn't get it to build on CircleCI because Node needed Python, Python 2 specifically, not Python 3, in order to build Node dependencies, particularly LibSass, I want to say, or node-sass. So node-sass needed Python 2, which I believe is end of life-d, to build a CSS authoring tool. And I kind of took a step back at that moment, and I was like, what did we do, everybody? What is going on here? And thankfully, I feel like there was more sort of unification of tools and simplification of the build tool space and whatnot. But I patched it, and I fixed some things, then finally I got it working. But then Memcache wasn't working, and I had to de-provision that and reprovision something. The amount of little...like, each thing that I fixed broke something else. I was like, the only thing I can do at this point is just burn the entire app down and rebuild it. Thankfully, I found a working version of things. But I think at some point, I've got to roll up my sleeves some weekend and do the full Rails, Ruby, everything upgrade, just get back to fresh. But my goodness, it was rough. STEPH: I feel like this is one of those reasons where we've talked in the past about you want to do something, and you keep putting it off. And it's like, if I had just sat down and done it, I could have knocked it out. Like, oh, it only took me like 5-10 minutes. But then there's this where you get excited, and then you want to dive in. And then suddenly, you do spend an hour or however long, and you're just focused on trying to get to the point where you can break ground and start building. I think that's the resistance that we're often fighting when we think about, oh, I'm going to keep delaying this because I don't know how long it's going to take. CHRIS: There's something that I see in certain programming communities, which is sort of a beginner-friendliness or a beginner's mindset or a welcomingness to beginners. I see it, particularly in the Svelte world, where they have a strong focus on being able to pick something up and run with it immediately. The entire tutorial is built as there's the tutorial on the one side, like the text, and then on the right side is an interactive REPL. And you're just playing with the Svelte REPL and poking around. And it's so tangible and immediate. And they're working on a similar thing now for SvelteKit, which is the meta-framework that does server-side rendering and all the fancy stuff. But I love the idea that that is so core to how the Svelte community works. And I'll be honest that other times, I've looked at it, and I've been like, I don't care as much about the first run experience; I care much more about the long-term maintainability of something. But it turns out that I think those two are more coupled than I had initially...like, how easy is it for a beginner to get started is closely related to or is, you know, the flip side of how easy is it for me to maintain that over time, to find the documentation, to not have a weird builder that no one else has ever seen. There's that wonderful XKCD where it's like, what's the saddest thing on the internet? Seeing the question that you have asked by one other person on Stack Overflow and no answers four years ago. It's like, yeah, that's painful. You actually want to be part of the boring, mundane, everybody's getting the same errors, and we have solutions to them. So I really appreciate when frameworks and communities care a lot about both that first run experience but also the maintainability, the error messages, the how okay is it for this system to segfault? Because it turns out segfaults prints some funny characters to your terminal. And so, like the range from human-friendly error message all the way through to binary character dump, I'm interested in folks that care about that space. But yeah, so that's just a bit of griping. I got through it. I made things work. I appreciate, again, the efforts that people are putting in to make that sad situation that I experienced not as common. But to highlight something that's really great and wonderful that I've been working with, there is a project called capybaratable. capybaratable is the gem name. And it is just this delightful little set of matchers that you can use within a Capybara, particularly within feature spec. So if you have a table, you can now make an assertion that's like, expect the table to have table row. And then you can basically pass it a hash of the column name and the value, but you can pass it any of the columns that you want. And you can pass it...basically, it reads exactly like the user would read it. And then, if there's an error, if it actually doesn't find it, if it misses the assertion, it will actually print out a little ASCII table for you, which is so nice. It's like, here's the table row that I saw. It didn't have what you were looking for, friend, sorry about that. And it's just so expressive. It forces accessibility because it basically looks at the semantic structure of a table. And if your table is not properly semantically structured, if you're not using TDs and TRs, and all that kind of stuff, then it will not find it. And so it's another one of those cases where testing can be a really useful constraint from the usability and accessibility of your application. And so, just in every way, I found this project works so well. Error messages are great. It forces you into a better way of building applications. It is just a wonderful little tool that I found. STEPH: That's awesome. I've definitely seen other thoughtboters when working in codebases that then they'll add really nice helper methods around that for like checking does this data exist in the table? And so I'm used to seeing that type of approach or taking that type of approach myself. But the ASCII table printout is lovely. That's so...yeah, that's just a nice cherry on top. I will have to lock that one away and use that in the future. CHRIS: Yeah, really, just such a delightful thing. And again, in contrast to the troubles of my weekend, it was very nice to have this one tool that was just like, oh, here's an error, and it's so easy to follow, and yeah. So it's good that there are good things in the world. But speaking of good things, what's new in your world? I hope good things. And I hope you're not about to be like, everything's terrible. But what's up with you? [laughter] STEPH: Everything's on fire. No, I do have some good things. So the good thing is that I'm preparing for...I have maternity leave that's coming up. So I am going to take maternity leave in about four-ish weeks. I know the date, but I'm saying the ish because I don't know when people are listening. [laughs] So I'm taking maternity leave coming up soon. I'm very excited, a little panicked mostly about baby preparedness, because, oh my goodness, it is such an overwhelming world, and what everyone thinks you should or shouldn't have and things that you need to do. So I've been ramping up heavily in that area. And then also planning for when I'm gone and then what that's going to look like for the team, and for clients, and for making sure I've got work wrapped up nicely. So that's a big project. It's just something that's on my mind, something that I am working through and making plans for. On the weird side, I ran into something because I'm still in test migration world. That is one of like, this is my mountain. This is my Everest. I am determined to get all of these tests. Thank you to everyone who has listened to me, especially you, listen to me talk about this test migration path I've been on and the journey that it's been. This is the goal that I have in mind that I really want to get done. CHRIS: I know that when you said, "Especially you," you were talking to me, Chris Toomey. But I want to imagine that every listener out there is just like, aww, you're welcome, Steph. So I'm going to pretend for my own sake that that's what you meant by, especially you. It's especially every one of you out there in the audience. STEPH: Yes, I love either version. And good point, because you're right, I'm looking at you. So I can say especially you since you've been on this journey with me, but everybody listening has been on this journey with me. So I've got a number of files left that I'm working through. And one of the funky things that I ran into, well, it's really not funky; it was a little bit more of an educational rabbit hole for me because it's something that I hadn't considered. So migrating over a controller test over from Test::Unit to then RSpec, there are a number of controller tests that issue requests or they call the same controller method multiple times. And at first, I didn't think too much about it. I was like, okay, well, I'm just going to move this over to RSpec, and everything is going to be fine. But based on the way a lot of the information is getting set around logging in a user and then performing an action, and then trying to log in a different user, and then perform another action that was causing mayhem. Because then the second user was never getting logged in because the first user wasn't getting logged out. And it was causing enough problems that Joël and I both sat back, and we're like, this should really be a request back because that way, we're going through the full Rails routing. We're going through more of the sessions that get set, and then we can emulate that full request and response cycle. And that was something that I just hadn't, I guess, I hadn't done before. I've never written a controller spec where then I was making multiple calls. And so it took a little while for me to realize, like, oh, yeah, controller specs are really just unit test. And they're not going to emulate, give us the full lifecycle that a request spec does. And it's something that I've always known, but I've never actually felt that pain point to then push me over to like, hey, move this to a request spec. So that was kind of a nice reminder to go through to be like, this is why we have controller specs. You can unit test a specific action; it is just hitting that controller method. And then, if you want to do something that simulates more of a user flow, then go ahead and move over to the request spec land. CHRIS: I don't know what the current status is, but am I remembering correctly that the controller specs aren't really a thing anymore and that you're supposed to just use request specs? And then there's features specs. I feel like I'm conflating...there's like controller requests and feature, but feature maybe doesn't...no, system, that's what I'm thinking of. So request specs, I think, are supposed to be the way that you do controller-like things anymore. And the true controller spec unit level thing doesn't exist anymore. It can still be done but isn't recommended or common. Does that sound true to you, or am I making stuff up? STEPH: No, that sounds true to me. So I think controller specs are something that you can still do and still access. But they are very much at that unit layer focus of a test versus request specs are now more encouraged. Request specs have also been around for a while, but they used to be incredibly slow. I think it was more around Rails 5 that then they received a big increase in performance. And so that's when RSpec and Rails were like, hey, we've improved request specs. They test more of the framework. So if you're going to test these actions, we recommend going for request specs, but controller specs are still there. I think for smaller things that you may want to test, like perhaps you want to test that an endpoint returns a particular status that shows that you're not authorized or forbidden, something that's very specific, I think I would still reach for a controller spec in that case. CHRIS: I feel like I have that slight inclination to the unit spec level thing. But I've been caught enough by different things. Like, there was a case where CSRF wasn't working. Like, we made some switch in the application, and suddenly CSRF was broken, and I was like, well, that's bad. And the request spec would have caught it, but the controller spec wouldn't. And there's lots of the middleware stack and all of the before actions. There is so much hidden complexity in there that I think I'm increasingly of the opinion, although I was definitely resistant to it at first, but like, yeah, maybe just go the request spec route and just like, sure. And they'll be a little more costly, but I think it's worth that trade-off because it's the stuff that you're not thinking about that is probably the stuff that you're going to break. It's not the stuff that you're like, definitely, if true, then do that. Like, that's the easier stuff to get right. But it's the sneaky stuff that you want your tests to tell you when you did something wrong. And that's where they're going to sneak in. STEPH: I agree. And yeah, by going with the request specs, then you're really leaning into more of an integration test since you are testing more of that request/response lifecycle, and you're not as likely to get caught up on the sneaky stuff that you mentioned. So yeah, overall, it was just one of those nice reminders of I know I use request specs. I know there's a reason that I favor them. But it was one of those like; this is why we lean into request specs. And here's a really good use case of where something had been finagled to work as a controller test but really rightfully lived in more of an integration request spec. MIDROLL 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 you cut your debugging time in half. So why do developers love Airbrake? Well, 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 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 enables 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 and includes 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. So head on over to airbrake.io/try/bikeshed to create your FREE developer account today! STEPH: Changing gears just a bit, I have something that I'd love to chat with you about. It came up while I was having a conversation with another thoughtboter as we were discussing how do you track velocity and know if you're working quickly enough? So since we often change projects about every six months, there's the question of how do I adapt to this team? Or maybe I'm still newish to thoughtbot or to a team; how do I know that I am producing the amount of work that the client or the team expects of me and then also still balancing that and making sure that I'm working at a sustainable pace? And I think that's such a wonderful, thoughtful question. And I have some initial thoughts around it as to how someone could track velocity. I also think there are two layers to this; there could be are we looking to track an individual's velocity, or are we looking to track team velocity? I think there are a couple of different ways to look at this question. But I'm curious, what are your thoughts around tracking velocity? CHRIS: Ooh, interesting. I have never found a formal method that worked in this space, no metric, no analysis, no tool, no technique that really could boil this down and tell a truth, a useful truth about, quote, unquote, "Velocity." I think the question of individual velocity is really interesting. There's the case of an individual who joins a team who's mostly working to try and support others on the team, so doing a lot of pairing, doing a lot of other things. And their individual velocity, the actual output of lines of code, let's say, is very low, but they are helping the overall team move faster. And so I think you'll see some of that. There was an episode a while back where we talked about heuristics of a team that's moving reasonably well. And I threw out the like; I don't know, like a pull request a day sort of thing feels like the only arbitrary number that I feel comfortable throwing out there in the world. And ideally, these pull requests are relatively small, individual deployable things. But any other version of it, like, are we thinking lines of code? That doesn't make sense. Is it tickets? Well, it depends on how you size your tickets. And I think it's really hard. And I think it does boil down to it's sort of a feeling. Do we feel like we're moving at a comfortable clip? Do I feel like I'm roughly keeping pace with the rest of the team, especially given seniority and who's been on the team longer? And all of those sorts of things. So I think it's incredibly difficult to ask about an individual. I have, I think, some more pointed thoughts around as a team how we would think about it and communicate about velocity. But I'm interested what came to mind for you when you thought about it, particularly for the individual side or for the team if you want to go in that direction. STEPH: Yeah, most of my initial thoughts were more around the individual because I think that's where this person was coming from because they were more interested in, like, how do I know that I'm producing as much as the team would expect of me? But I think there's also the really interesting element of tracking a team's velocity as well. For the individual, I think it depends a lot on that particular team and their goals and what pace they're moving at. So when I do join a new team, I will look around to see, okay, well, what's the cadence? What's the standard bar for when someone picks up a ticket and then is able to push it through? How much cruft are we working with in the codebase? Because then that will change the team's expectations of yes, we know that we have a lot of legacy code that we're working with, and so it does take us longer to get through things. And that is totally fine because we are looking more to optimize our sustainability and improving the code as we go versus just trying to get new features in. I think there's also an important cultural aspect. So some teams may, unfortunately, work a lot of extra hours. And that's something that I won't bend for. I'm still going to stick to my sustainable hours. But that's something that I keep in mind that just if some other people are working a lot of evenings or just working extra hours to keep that in mind that if they do have a higher velocity to not include that in my calculation as heavily. I also really liked how you highlighted that certain individuals often their velocity is unblocking others. So it's less about the specific code or features or tickets that they're producing, but it's how many people can they help? And then they're increasing the velocity of those individuals. And then the other metrics that unfortunately can be gamified, but it's still something to look at is like, how many hours are you spending on a particular feature, the tickets? But I like that phrasing that you used earlier of what's your progress? So if someone comes to daily sync and they mention that they're working on the same thing and we're on like day three, or four, but they haven't given an update around, like, oh, I have this new thing that I'm focused on, or this new area that I'm exploring, that's when I'll start to have alarm bells go off. And I'm like, okay, you've been working on the same thing. I can't quite tell if you've made progress. It sounds like you're still in the depths of the original thing that you were on a couple of days ago. So at that point, I'm going to want to check in to see how you're doing. But yeah, I think that's why this question fascinates me so much is because I don't think there's one answer that fits for everybody. There's not a way to tell one person to say, "Hey, this is your output that you should be producing, and this applies to all teams." It's really going to vary from team to team as to what that looks like. I remember there was one team that I joined that initially; I panicked because I noticed that their team was moving at a slower rate in terms of the number of tickets and PRs and stuff that were getting pushed up, reviewed, and then merged. That was moving at a slower pace than I was used to with previous clients. And I just thought, oh, what's going on? What's slowing us down? Like, why aren't we moving faster? And I actually realized it's just because they were working at a really sustainable pace. They showed up to the office. This was back in the day when I used to go to an office, and people showed up at like 9:00 a.m. and then 5:00 o'clock; it was a ghost town, and people were gone. So they were doing really solid, great work, but they were sticking to very sustainable hours. Versus, a previous team that I had been on had more of like a rushed feeling, and so there was more output for it. And that was a really nice reset for me to watch this team and see them do such great work in a sustainable fashion and be like, oh, yeah, not everything has to be a fire, not everything has to be rushed. I think the biggest thing that I'd look at is if velocity is being called into question, so if someone is concerned that someone's not producing enough or if the team is not producing enough, the first place I'm going to look is what's our priorities and see are we prioritizing correctly? Or are people getting pulled into a lot of work that's not supporting the priorities, and then that's why suddenly it feels like we're not producing at the level that we need to? I feel like that's the common disconnect between how much work we're getting done versus then what's actually causing people or product managers, or management stress. And so reevaluating to make sure that they're on the same page is where I would look first before then thinking, oh, someone's not working hard enough. CHRIS: Yeah, I definitely resonate with all of that. That was a mini masterclass that you just gave right there in all of those different facets. The one other thing that comes to mind for me is the question is often about velocity or speed or how fast can we go. But I increasingly am of the opinion that it's less about the actual speed. So it's less about like, if you think about it in terms of the average pace, the average number of features that we're going through, I'm more interested in the standard deviation. So some days you pick up a ticket, and it takes you a day; some days you pick up a ticket, and suddenly, seven days later, you're still working on it. And both at the individual level and at the team level, I'm really interested in decreasing that standard deviation and making it so that we are more consistently delivering whatever amount of output it is but very consistently doing that. And that really helps with our ability to estimate overall bodies of work with our ability for others to know and for us to be able to sort of uphold expectations. Versus if randomly someone might pick up a piece of code or might pick up a ticket that happens to hit a landmine in the code, it's like, yeah, we've been meaning to refactor that for a while. And it turns out that thing that you thought would be super easy is really hard because we've been kicking the can on this refactoring of the fundamental data model. Sorry about that. But today's your day; you lose. Those are the sort of things that I see can be really problematic. And then similarly, on an individual side, maybe there's some stuff that you can work on that is super easy for you. But then there's other stuff that you kind of hit a wall. And I think the dangerous mode to get into is just going internal and not really communicating about that, and struggling and trying to get there on your own rather than asking for help. And it can be very difficult to ask for help in those sorts of situations. But ideally, if you're focusing on I want to be delivering in that same pace, you probably might need some help in that situation. And I think having a team that really...what you're talking about of like, if I notice someone saying the same thing at daily sync for a couple of days in a row, I will typically reach out in a very friendly, collegial way, hey, do you want someone else to take a look at that with you? Because ideally, we want to unblock those situations. And then if we do have a team that is pretty consistently delivering whatever overall velocity but it's very consistent at that velocity, it's not like 3 one day and then 0, and then 12, and then 2; it's more of like, 6,5,6,5 sort of thing, to pick random numbers out of the air, then I feel so much more able to grow that, to increase that. If the question comes to me of like, hey, we're looking at the budget for the next quarter; do we think we want to hire another developer? I think I can answer that much more accurately at that point and say what do I think that additional individual would be able to do on the team. Versus if development is kind of this sporadic thing all over the place, then it's so much harder to understand what someone new joining that team would be able to do. So it's really the slow is smooth, smooth is fast adage that I've talked about in the past that really captured my mind a while back that just continues to feel true to me. And then yeah, I can work with that so much better than occasional days of wild productivity and then weeks of sadness in the swamp of refactoring. So it's a different way to think about the question, but it is where my mind initially went when I read this question. STEPH: I'm going to start using that description for when I'm refactoring. I'm in the refactoring swamp. That's where I'm spending my time. [laughs] Talking about this particular question is helping me realize that I do think less in terms of like what is my output in the strict terms of tickets, and PRs, and things like that. But I do think more about my progress and how can I constantly show progress, not just to the world but show it to myself. So if there are tickets that then maybe the ticket was scoped too big at first and I've definitely made some really solid progress, maybe I'm able to ship something or at least identified some other work that could be broken out, then I'm going to do that. Because then I want everybody to know, like, hey, this is the progress that was made here. And I may even be able to make myself feel good and move something over to the done column. So there's that aspect of the work that I focus on more heavily. And I feel like that also gives us more opportunities to then iterate on what's the goal? Like, we're not looking to just churn out work. That's not the point. But we really want to focus on meaningful work to get done. So if we're constantly giving an update on this as the progress that I've made in this direction, that gives people more opportunities to then respond to that progress and say, "Oh, actually, I think the work was supposed to do this," or "I have questions about some of the things that you've uncovered." So it's less about just getting something done. But it's still about making sure that we're working on the right thing. CHRIS: Yeah, it doesn't matter how fast we're going if we're going in the wrong direction, so another critical aspect. You can be that person on the team who actually doesn't ship much code at all. Just make sure that we don't ship the wrong code, and you will be a critical member of that team. But shifting gears just a little bit, we have another listener question here that I'd love to get into. This one is about testing a legacy app. So reading this question, it starts off with a very nice note to us, Steph. "I want to start by saying thanks for putting out great content week after week." We are very happy to do so." So a question for you two. I just took over a legacy Rails app. It's about 12 years old, and it's a bit of a mess. There was some testing in place, but it was completely broken and hadn't been touched in over seven years. So I decided to just delete it all. My question is, where do I even start with testing? There are so many callbacks on the models and so many controller hooks that I feel like I somehow need to have a factory for every model in our repo. I need to get testing in place ASAP because that is how I develop. But we are also still on Ruby 2 and Rails 4.0. So we desperately have to upgrade. Thanks in advance for any advice." So Steph, I actually replied in an email to this kind listener who sent this. And so, I definitely have some thoughts, but I'm interested in where would you start with this. STEPH: Legacy code, I wouldn't know anything about working in legacy code. [laughs] This is a fabulous question. And yeah, the response that you provided is incredible. So I'm very excited for you to share the message that you replied with. So I'm going to try not to steal any of those because they're wonderful. But to add to that list that is soon to come, often where I start with applications like these where I need some testing in place because, as this person mentioned, that's how they work. And then also, at that point, you're just scared to ship anything because you just don't know what's going to break. So one area that you could start with is what's your rollback strategy? So if you don't have any tests in place and you send something out into the world, then what's your plan to then be able to either roll back to a safe point or perhaps it's using feature flags for anything new that you're adding so that way you can quickly turn something on and off. But having a strategy there, I think, will help alleviate some of that stress of I need to immediately add tests. It's like, yes, that's wonderful, but that's going to take time. So until you can actually write those tests, then let's figure out a plan to mitigate some of that pain. So that's where I would initially start. And then, as for adding the test, typically, you start with testing as you go. So I would add tests for the code that I'm adding that I'm working on because that's where I'm going to have the most context. And I'm going to start very high. So I might have really slow tests that test everything that is going to be feature level, integration level specs because I'm at the point that I'm just trying to document the most crucial user flows. And then once I have some of those in place, then even if they are slow, at least I'm like, okay, I know that the most crucial user flows are protected and are still working with this change that I'm making. And in a recent episode, we were talking about how to get to know a Rails app. You highlighted a really good way to get to know those crucial user flows or the most common user flows by using something like New Relic and then seeing what are the paths that people are using. Maybe there's a product manager or just someone that you're taking the app over that could also give you some help in letting you know what's the most crucial features that users are relying on day to day and then prioritizing writing tests for those particular flows. So then, at this point, you've got a rollback strategy. And then you've also highlighted what are your most crucial user flows, and then you've added some really high level probably slow tests. Something that I've also done in the past and seen others do at thoughtbot when working on a legacy project or just working on a project, it wasn't even legacy, but it just didn't have any test coverage because the team that had built it before hadn't added test coverage. We would often duplicate a lot of the tests as well. So you would have some integration tests that, yes, frankly, were very similar to others, which felt like a bad choice. But there was just some slight variation where a user-provided some different input or clicked on some small different field or something else happened. But we found that it was better to have that duplication in the test coverage with those small variations versus spending too much time in finessing those tests. Because then we could always go back and start to improve those tests as we went. So it really depends. Are you in fire mode, and maybe you need to duplicate some stuff? Or are you in a state where you can be more considerate with your tests, and you don't need to just get something in place right away? Those are some of the initial thoughts I have. I'm very excited for the thoughts that you're about to share. So I'm going to turn it over to you. CHRIS: It's sneaky in this case. You have advanced notice of what I'm about to say. But yeah, this is a super interesting topic and one of those scary places to find yourself in. Very similar to you, the first thing that I recommended was feature specs, starting at that very high level, particularly as the listener wrote in and saying there are a lot of model callbacks and controller callbacks. And before filters and all of this, it's very indirect how this application works. And so, really, it's only when the whole thing is integrated together that you're going to have a reasonable sense of what's going on. And so trying to write those high-level feature specs, having a handful of them that give you some confidence when you're deploying that those core workflows are still working as expected. Beyond that, the other things that I talked about one was observability. As an aside, I didn't mention feature flags or anything like that. And I really loved that that was something you highlighted as a different way to get to confidence, so both feature flags and rollbacks. Testing at the end of the day, the goal is to have confidence that we're deploying software that works, and a different way to get that is feature flags and rollbacks. So I really love that you highlighted that. Something that goes really well hand in hand with those is observability. This has been a thing that I've been exploring more and more and just having some tooling that at runtime will tell you if your application is behaving as expected or is not. So these can be APM-type tools, but it can also be things like Sentry or Honeybadger error monitoring, those sorts of things. And in a system like this, I wouldn't be surprised if maybe there was an existing error monitoring tool, but it had just kind of decayed over time and now just has perhaps thousands of different entries in it that have been ignored and whatnot. On more than one occasion, I've declared Sentry bankruptcy working with clients and just saying like, listen; this thing can't tell us any truths anymore. So let's burn it down and restart it. So I would recommend that and having that as a tool such that much as tests are really wonderful before the code gets out there into the wild; it turns out it's only when users start using it that the real stuff happens. And so, having observability, having tooling in place that will tell you when something breaks is equally critical in my mind. One of the other things I said, and this is probably the spiciest take on my list, is questioning the trade-off space that you're in. Is this an application that actually has a relatively low defect rate that users use and are quite happy with, and expect that level of performance and correctness, and all of those sorts of things, and so you, frankly, need to be careful with it? Or, is it potentially something that has a handful of bugs and that users are used to a certain lower fidelity experience, let's call it? And can you take advantage of that if that happens to be true? Like, I would be very careful to break something that has never been broken before that there's no expectation of that. But if we can get away with moving fast and breaking things for a little while just to try and get ourselves out of the spot that we're in, I would at least want to consider that trade-off space. Because caution slows you down, it means that your progress is going to be limited. And so, if we're able to reduce the caution filter just a little bit and move a little bit more rapidly, then ideally, we can get out of this place that we're in a little more quickly. Again, I think that's a really subtle one and one that you'd have to get buy-in from product managers and probably be very explicit in the conversations and sort of that trade-off space. But it is something that I would want to explore if I found myself in this sort of situation. The last thing that I highlighted was the fact that the versions of Ruby and Rails that were listed in the question are, I think, both end of life at this point. And so from a security perspective, that is just a giant glaring warning sign in the corner because the day that your app gets hacked, well, that's a bad day. So testing, unfortunately, I think that's the main way that you're going to get by on that as you're going through upgrades. You can deploy a new version of the application and see what happens and see if your observability can get you there. But really, testing is what you want to do. So that's where building out that testing is all the more critical so that you can perform those security upgrades because they are now truly critical to get done. And so it gives sort of more than a nice to have, more than this makes me feel comfortable. It is pretty much a necessity if you want to go through that, and you absolutely need to go through the security upgrades because otherwise, you're going to get hacked. There are just automated scanners out there. They're going to find you. You don't need to be a high vulnerability target to get taken down on the internet these days. So if it hasn't happened yet, it's going to. And I think that's an easy business case to sell is, I guess, the way that I would frame it. So those were some of my thoughts. STEPH: You bring up a really good point about needing to focus on the security upgrades. And I'm thinking that through a little bit further in regards to what trade-offs would I make? Would I wait till I have tests in place to then start the upgrades, or would I start the upgrades now but just know I'm going to spend more time manual testing on staging? Or maybe I'm solo on the project. If I have a product manager or someone else that can also help the testing with me, I think I would go for that latter approach where I would start the upgrades today and then just do more manual testing of those crucial flows and then have that rollback strategy. And as you mentioned, it's a trade-off in terms of, like, how important is it that we don't break anything? CHRIS: I think similar to the thing that both of us hit on early on is like, have some feature specs that just kick the whole application as one connected piece of code. Have that in place for the security upgrade, testing. But I agree, I wouldn't want to hold off on that because I think that's probably the scariest part of all of this. But yeah, it is, again, trade-offs. As always, it depends. But I think those are my thoughts. Anything else you want to add, Steph? STEPH: I think those are fabulous thoughts. I think you covered it all. CHRIS: Sounds good. Well, in that case, should we wrap up? STEPH: Let's wrap up. CHRIS: The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeeee!!!!!!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

The Bike Shed
346: Occasional Biscuits

The Bike Shed

Play Episode Listen Later Jul 19, 2022 37:13


Natural disaster movies, anyone? It's what Steph's been into, and Chris has THOUGHTS on the drilling in Armageddon. Additionally, a chat around RuboCop RSpec rules happens, and they answer a listener's question, "how do you get acquainted with a new code base?" This episode is brought to you by BuildPulse (https://buildpulse.io/bikeshed). Start your 14-day free trial of BuildPulse today. Greenland (https://www.imdb.com/title/tt7737786/) Geostorm (https://www.imdb.com/title/tt1981128/) San Andreas (https://www.imdb.com/title/tt2126355/) Armageddon (https://www.imdb.com/title/tt0120591/) 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. Become a Sponsor (https://thoughtbot.com/sponsorship) of The Bike Shed! Transcript: AD: Flaky tests take the joy out of programming. You push up some code, wait for the tests to run, and the build fails because of a test that has nothing to do with your change. So you click rebuild, and you wait. Again. And you hope you're lucky enough to get a passing build this time. Flaky tests slow everyone down, break your flow, and make things downright miserable. In a perfect world, tests would only break if there's a legitimate problem that would impact production. They'd fail immediately and consistently, not intermittently. But the world's not perfect, and flaky tests will happen, and you don't have time to fix all of them today. So how do you know where to start? BuildPulse automatically detects and tracks your team's flaky tests. Better still, it pinpoints the ones that are disrupting your team the most. With this list of top offenders, you'll know exactly where to focus your effort for maximum impact on making your builds more stable. In fact, the team at Codecademy was able to identify their flakiest tests with BuildPulse in just a few days. By focusing on those tests first, they reduced their flaky builds by more than 68% in less than a month! And you can do the same because BuildPulse integrates with the tools you're already using. It supports all of the major CI systems, including CircleCI, GitHub Actions, Jenkins, and others. And it analyzes test results for all popular test frameworks and programming languages, like RSpec, Jest, Go, pytest, PHPUnit, and more. So stop letting flaky tests slow you down. Start your 14-day free trial of BuildPulse today. To learn more, visit buildpulse.io/bikeshed. That's buildpulse.io/bikeshed. CHRIS: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Chris Toomey. STEPH: And I'm Steph Viccari. CHRIS: And together, we're here to share a bit of what we've learned along the way. So, Steph, what's new in your world? STEPH: Hey, Chris. So I've been watching more movies lately. So evenings aren't always great; I don't always feel good being around 33 weeks pregnant now. Evenings I can be just kind of exhausted from the day, and I just need to chill and prop my feet up and all that good stuff. And I've been really drawn to natural disaster like end-of-the-world-type movies, and I'm not sure what that says about me. But it's my truth; it's where I'm at. [chuckles] I watched Greenland recently, which I really enjoyed. I feel like they ended it well. I won't share any spoilers, but I feel like they ended it well. And they didn't take an easy shortcut out that I kind of thought that they might do, so that one was enjoyable. Geostorm, I watched that one just last night. San Andreas, I feel like that's one that I also watched recently. So yeah, that's what's new in my world, you know, your typical natural disaster end-of-the-world flicks. That's my new evening hobby. CHRIS: I feel like I haven't heard of any of the three that you just listed, which is wild to me because this is a category that I find enthralling. STEPH: Well, definitely start with Greenland. I feel like that one was the better of the three that I just mentioned. I don't know Geostorm or San Andreas which one you would prefer there. I feel like they're probably on par with each other in terms of like you're there for entertainment. We're not there to judge and be hypercritical of a storyline. You're there purely for the visual effects and for the ride. CHRIS: Gotcha. Interesting. So quick question then, since this seems like the category you're interested in, Armageddon or Deep Impact? STEPH: Ooh, I'm going to have to walk through the differences because I always get those mixed up. Armageddon is where they take Bruce Willis up to an asteroid, and they have to drill and drop a nuke, right? CHRIS: They sure do. STEPH: [laughs] And then what's Deep Impact about? I guess the fact that I know Armageddon better means I'm favoring that one. I can't place what...how does Deep Impact go? CHRIS: Deep Impact is just there's an asteroid coming, and it's the story and what the people do. So it's got less...it doesn't have the same pop. I believe Armageddon was a Michael Bay movie. And so it's got that Michael Bay special bit of something on it. But the interesting thing is they came out the same year; I want to say. It's one of those like Burger King and McDonald's being right next door to each other. It's like, what are you doing there? Why are you...like, asteroid devastation movies two of you at the same time, really? But yeah, Armageddon is the correct answer. Deep Impact is like a fine movie, but Armageddon is like, all right, we're going to have a movie about asteroids. Let's really go for it. Blow it out. Why not? STEPH: Yeah, I'm with you. Armageddon definitely sticks out in my memory, so I'd vote that one. Also, for your other question that you didn't ask, but you kind of implicitly asked, I'm going to go McDonald's because Burger King fries are trash, and also, McDonald's has better ice cream cones. CHRIS: Okay, so McDonald's fries. Oh no, I was thinking Wendy's, get a frosty from there, and then you make that combination because the frostys are great. STEPH: Oh yeah, that's a good combo. CHRIS: And you need the french fries to go with it, but then it's a third option that I'm introducing. Also, this wasn't a question, but I want to loop back briefly to Armageddon because it's an important piece of cinema. There's a really great...like it's DVD commentary, and it's Ben Affleck talking with Michael Bay about, "Hey, so in the movie, the premise is that the only way to possibly get this done is to train a bunch of oil drillers to be astronauts. Did we consider it all just having some astronauts learn to do oil drilling?" And Michael Bay's response is not safe for radio is how I would describe it. But it's very humorous hearing Ben Affleck describe Michael Bay responding to that. STEPH: I think they addressed that in the movie, though. They mentioned like, we're going to train them, but they're like, no, drilling is such an art and a science. There's no way. We don't have time to teach these astronauts how to drill. So instead, it's easier to teach them to be astronauts. CHRIS: Right. That is what they say in the movie. STEPH: [laughs] Okay. CHRIS: But just spending a minute teasing that one apart is like, being an astronaut is easy. You just sit in the spaceship, and it goes, boom. [laughs] It's like; actually, there's a little bit more to being an astronaut. Yes, drilling is very subtle science and art fusion. But the idea that being an astronaut [laughs] is just like, just push the go-to space button, then you go to space. STEPH: The training montage is definitely better if we get to watch people learn how to be astronauts than if we watch people learn how to drill. [laughs] So that might have also played a role. CHRIS: No question, it is the correct cinematic choice. But whether or not it's the true answer...say we were actually faced with this problem, I don't know that this is exactly how it would play out. STEPH: I think we should A/B test it. We'll have one group train to be drill experts and one group train to be astronauts, and we'll send them both up. CHRIS: This is smart. That's the way you got to do it. The one other thing that I'm going to go...you know what really grinds my gears? In the movie Armageddon, they have this robotic vehicle thing, the armadillo; I believe it's called. I know more than I thought I would remember about this movie. [chuckles] Anyway, continuing on, the armadillo, the vehicle that they use to do the drilling, has the drill arm on it that extends out and drills down into the asteroid. And it has gears on the end of it. It has three gears specifically. And the first gear is intermeshed with the second gear, which is intermeshed with the third gear, which is intermeshed with the first gear, so imagine which direction the first gear is turning, then imagine the second gear turning, then imagine the third gear turning. They can't. It's a physically impossible object. One tries to turn clockwise, and the other one is trying to go counterclockwise, and they're intermeshed. So the whole thing would just cease up. It just doesn't work. I've looked at it a bunch of times, and I want to just be wrong about this. I want to be like; I don't know what's going on. But I think the gears on the drilling machine just fundamentally at a very simple mechanical level cannot work. And again, if you're going to do it, really go for it, Michael Bay. I kind of like that, and I really hate it at the same time. STEPH: I have never noticed this. I'm intrigued. You know what? Maybe Armageddon will be the movie of choice tonight. [chuckles] Maybe that's what I'm going to watch. And I'm going to wait for the armadillo to come out so I can evaluate the gears. And I'm highly amused that this is the thing that grinds your gears are the gears on the armadillo. CHRIS: Yeah. I was a young child at the time, and I remember I actually went to Disney World, and I saw they had the prop vehicle there. And I just kind of looked up at it, and I was like, no, that's not how gears work. I may have been naive and wrong as a child, and now I've just anchored this memory deep within me. In a similar way, so I had a moment while traveling; actually, that reminded me of something that I said on a recent podcast episode where I was talking about names and pronunciation. And I was like, yeah, sometimes people ask me how to pronounce my name. And I can't imagine any variation. That was the thing I was just wrong about because 'Toomay' is a perfectly reasonable pronunciation of my name that I didn't even think... I was just so anchored to the one truth that I know in the world that my name is Toomey. And that's the only possible way anyone could pronounce it. Nope, totally wrong. So maybe the gears in Armageddon actually work really, really well, and maybe I'm just wrong. I'm willing to be wrong on the internet, which I believe is the name of the first episode that we recorded with you formally as a co-host. [chuckles] So yeah. STEPH: Yeah, that sounds true. So you're going to change the intro? It's now going to be like, and I'm Chris 'Toomay'. CHRIS: I might change it each time I come up with a new subtle pronunciation. We'll see. So far, I've got two that I know of. I can't imagine a third, but I was wrong about one. So maybe I'm wrong about two. STEPH: It would be fun to see who pays attention. As someone who deeply values pronouncing someone's name correctly, oh my goodness, that would stress me out to hear someone keep pronouncing their name differently. Or I would be like, okay, they're having fun, and they don't mind how it gets pronounced. I can't remember if we've talked about this on air but early on, I pronounced my last name differently for like one of the first episodes that we recorded. So it's 'Vicceri,' but it could also be 'Viccari'. And I've defaulted at times to saying 'Viccari' because people can spell that. It seems more natural. They understand it's V-I-C-C-A-R-I. But if I say 'Vicceri', then people want to add two Rs, or they want a Y. I don't know why it just seems to have a difference. And so then I was like, nope, I said it wrong. I need to say it right. It's 'Vicceri' even if it's more challenging for people. And I think Chad Pytel had just walked in at that moment when I was saying that to you that I had said my name differently. And he's like, "You can't do that." And I'm like, "Well, I did it. It's already out there in the world." [laughs] But also, I'm one of those people that's like, Viccari, 'Vicceri' I will accept either. In a slightly different topic and something that's going on in my world, there was a small win today with a client team that I really appreciated where someone brought up the conversation around the RuboCop RSpec rules and how RuboCop was fussing at them because they had too many lines in their test example. And so they're like, well, they're like, I feel like I'm competing, or I'm working against RuboCop. RuboCop wants me to shorten my test example lines, but yet, I'm not sure what else to do about it. And someone's like, "Well, you could extract more into before blocks and to lets and to helpers or things like that to then shorten the test. They're like, "But that does also work against readability of the test if you do that." So then there was a nice, short conversation around well, then we really need more flexibility. We shouldn't let the RuboCop metrics drive us in this particular decision when we really want to optimize for readability. And so then it was a discussion of okay, well, how much flexibility do we add to it? And I was like, "Well, what if we just got rid of it? Because I don't think there's an ideal length for how long your test should be. And I'd rather empower test authors to use all the space that they need to show their test setup and even lean into duplication before they extract things because this codebase has far more dry tests than they do duplication concerns. So I'd rather lean into the duplication at this point." And the others that happened to be in that conversation were like, "Yep, that sounds good." So then that person issued a PR that then removed the check for that particular; how long are the examples? And it was lovely. It was just like a nice, quick win and a wonderful discussion that someone had brought up. CHRIS: Ooh, I like that. That sounds like a great conversation that hit on why do we have this? What are the trade-offs? Let's actually remove it. And it's also nice that you got to that place. I've seen a lot of folks have a lot of opinions in the past in this space. And opinions can be tricky to work around, and just deeply, deeply entrenched opinions is the thing that I find interesting. And I think I'm increasingly in the space of those sort of, thou shalt not type linter rules are not ideal in my mind. I want true correctness checks that really tell some truth about the codebase. Like, we still don't have RuboCop on our project at Sagewell. I think that's true. Yeah, that's true. We have ESLint, but it's very minimal, what we have configured. And they more are in the what we deem to be true correctness checks, although that is a little bit of a blurry line there. But I really liked that idea. We turn on formatters. They just do the thing. We're not allowed to discuss the formatting, with the exception of that time that everybody snuck in and switched my 80-line length to a 120-line length, but I don't care. I'm obviously not still bitter about it. [chuckles] And then we've got a very minimal linting layer on top of that. But like TypeScript, I care deeply, and I think I've talked in previous episodes where I'm like, dial up the strictness to 14 because TypeScript tends to tell me more truths I find, even though I have to jump through some hoops to be like TypeScript, I know that this is fine, but I can't prove it. And TypeScript makes me prove it, which I appreciate about it. I also really liked the way you referred to RSpec's feedback to you was that RSpec was fussing at you. That was great. I like that. I'm going to internalize that. Whenever a linter or type system or anything like that when they tell me no, I'm going to be like, stop fussing, nope, nope. [chuckles] STEPH: I don't remember saying that, but I'm going to trust you that that's what I said. That's just my true southern self coming through on the mic, fussing, and then go get a biscuit, and it'll just be a delightful day. CHRIS: So if I give RuboCop a biscuit, it will stop fussing at me, potentially? STEPH: No, the biscuit is just for you. You get fussed at; you go get a biscuit. It makes you feel better, and then you deal with the fussing. CHRIS: Sold. STEPH: Fussing and cussing, [laughs] that's most of my work life lately, fussing and cussing. [laughs] CHRIS: And occasional biscuits, I hope. STEPH: And occasional biscuits. You got it. But that's what's new in my world. What's going on in your world? CHRIS: Let's see. In my world, it's a short week so far. So recording on Wednesday, Monday was a holiday. And I was out all last week, which very much enjoyed my vacation. It was lovely. Went over to Europe, hung out there for a bit, some time in Paris, some time in Amsterdam, precious little time on a computer, which is very rare for me. So it was very enjoyable. But yeah, back now trying to just get back into the swing of things. Thankfully, this turned out to be a really great time to step away from the work for a little while because we're still in this calm before the storm but in a good way is how I would describe it. We have a major facet of the Sagewell platform that we are in the planning modes for right now. But we need to get a couple of different considerations, pick a partner vendor, et cetera, that sort of thing. So right now, we're not really in a position to break ground on what we know will be a very large body of work. We're also not taking on anything else too big. We're using this time to shore up a lot of different things. As an example, one of the fun things that we've done in this period of time is we have a lot of webhooks in the app, like a lot of webhooks coming into the app, just due to the fact that we're an integration of a lot of services under the hood. And we have a pattern for how we interact with and process, so we actually persist the webhook data when they come in. And then we have a background job that processes and watch our pattern to make sure we're not losing anything and the ability to verify against our local version, and the remote version, a bunch of different things. Because turns out webhooks are critical to how our app works. And so that's something that we really want to take very seriously and build out how we work with that. I think we have eight different webhook integrations right now; maybe it's more. It's a lot. And with those, we've implemented the same pattern now eight times; I want to say. And in squinting at it from a distance, we're like; it is indeed identically the same pattern in all eight cases or with the tiniest little variation in one of them. And so we've now accepted like, okay, that's true. So the next one of them that we introduced, we opted to do it in a generic way. So we introduced the abstraction with the next iteration of this thing. And now we're in a position...we're very happy with what we ended up with there. It's like the best of all of the other versions of it. And now, the plan will be to slowly migrate each of the existing ones to be no longer a unique special version of webhook processing but use the generic webhook processing pattern that we have in the app. So that's nice. I feel good about how long we waited as well because it's like, we have webhooks. Let's introduce the webhook framework to rule them all within our app. It's like, no, wait until you see. Check and make sure they are, in fact, the same and not just incidental duplication. STEPH: I appreciate that so much. That's awesome. That sounds like a wonderful use of that in-between state that you're in where you still got to make progress but also introduce some refactoring and a new concept. And I also appreciate how long you waited because that's one of those areas where I've just learned, like, just wait. It's not going to hurt you. Just embrace the duplication and then make sure it's the right thing. Because even if you have to go in and update it in a couple of places, okay, sure, that feels a little tedious, but it feels very safe too. If it doesn't feel safe...I could talk myself back and forth on this one. If it doesn't feel safe, that's a different discussion. But if you're going through and you have to update something in a couple of different places, that's quick. And sure, you had to repeat yourself a little bit, but that's fine. Versus if you have two or three of something and you're like, oh, I immediately must extract. That's probably going to cause more pain than it's worth at this point. CHRIS: Yeah, exactly, exactly that. And we did get to that place where we were starting to feel a tiny bit of pain. We had a surprising bit of behavior that when we looked at it, we were like, oh, that's interesting, because of how we implemented the webhook pattern, this is happening. And so then we went to fix it, but we were like, oh, it would actually be really nice to have this fixed across everything. We've had conversations about other refinements, enhancements, et cetera; that we could do in this space. That, again, would be really nice to be able to do holistically across all of the different webhook integration things that we have. And so it feels like we waited the right amount of time. But then we also started to...we're trying to be very responsive to the pressure that the system is pushing back on us. As an aside, the crispy Brussels snack hour and the crispy Brussels work lunch continue to be utterly fantastic ways in which we work. For anyone that is unfamiliar or hasn't listened to episodes where I rambled about those nonsense phrases that I just said, they're basically just structured time where the engineering team at Sagewell looks at and discusses higher-level architecture, refactoring, developer experience, those sort of things that don't really belong on the core product board. So we have a separate place to organize them, to gather them. And then also, we have a session where we vote on them, decide which ones feel important to take on but try and make sure we're being intentional about how much of that work we're taking on relative to how much of core product work and try and keep sort of a good ratio in between the two. And thus far, that's been really fantastic and continues to be, I think, really effective. And also the sort of thing that just keeps the developer team really happy. So it's like, I'm happy to work in this system because we know we have a way to change it and improve it where there's pain. STEPH: I like the idea of this being a game show where it's like refactor island, and everybody gets together and gets to vote which refactor stays or gets booted off the island. I'm also going to go back and qualify something I said a moment ago, where if something feels safe in terms of duplication, where it starts to feel unsafe is if there's like an area that you forgot to update because you didn't realize it's duplicated in several areas and then that causes you pain. Then that's one of those areas where I'll start to say, "Okay, let's rethink the duplication and look to dry this up." CHRIS: Yep, indeed. It's definitely like a correction early on in my career and overcorrection back and trying to find that happy medium place. But as an aside, just throwing this out there, so webhooks are an interesting space. I wish it were a more commoditized offering of platforms. Every vendor that we're integrating with that does webhooks does it slightly differently. It's like, "Oh, do you folks have retries?" They're like, "No." It's like, oh, what do you mean no? I would love it if you had retries because, I don't know, we might have some reason to not receive one of them. And there's polling, and there are lots of different variations. But the one thing that I'm surprised by is that webhook signing I don't feel like people take it serious enough. It is a case where it's not a huge security vulnerability in your app. But I was reading someone who is a security analyst at one point. And they were describing sort of, I've done tons of in-the-code audits of security practices, and here are the things that I see. And so it's the normal like OWASP Top 10 Cross-Site Request Forgery, and SQL injection, and all that kind of stuff. But one of the other ones he highlighted is so often he finds webhooks that are not verified in any way. So it's just like anyone can post data into the system. And if you post it in the right shape, the system's going to do some stuff. And there's no way for the external system to enforce that you properly validate and verify a webhook coming in, verify that payload. It's an extra thing where you do the checksum math and whatnot and take the signature header. I've seen somewhere they just don't provide it. And it's like, what do you mean you don't provide it? You must provide it, please. So it's either have an API key so that we have some way to verify that you are who you say you are or add a signature, and then we'll calculate it. And it's a little bit of a dance, and everybody does it different, but whatever. But the cases where they just don't have it, I'm like, I'm sorry, what now? You're going to say whom? But yeah, then it's our job to definitely implement that. So this is just a notice out there to anyone that's listening. If you got a bunch of webhook handling code in your app, maybe spot-check that you're actually verifying the payloads because it's possible that you're not. And that's a weird, very open hole in the side of your application. STEPH: That's a really great point. I have not worked with webhooks recently. And in the past, I can't recall if that's something that I've really looked at closely. So I'm glad you shared that. CHRIS: It's such an easy thing to skip. Like, it's one of those things that there's no way to enforce it. And so, I'd be interested in a survey that can't be done because this is all proprietary data. But what percentage of webhook integrations are unverified? Is it 50%? Is it 10%? Is it 100%? It's definitely not 100. But it's somewhere in there that I find interesting. It's not a terribly exploitable vulnerability because you have to have deep knowledge of the system. In order to take advantage of it, you need to know what endpoint to hit to, what shape of data to send because otherwise, you're probably just going to cause an error or get a bunch of 404s. But like, it's, I don't know, it's discoverable. And yeah, it's an interesting one. So I will hop off my webhook soapbox now, but that's a thought. MIDROLL 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 you cut your debugging time in half. So why do developers love Airbrake? Well, 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 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 enables 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 and includes 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. So head on over to airbrake.io/try/bikeshed to create your FREE developer account today! CHRIS: But now that I'm off my soapbox, I believe we have a topic that was suggested. Do you want to provide a little bit of context here, Steph? STEPH: Yeah, I'd love to. So this came up when I was having a conversation with another thoughtboter. And given that we change projects fairly frequently, on the Boost team, we typically change projects around every six months. They asked a really thoughtful question that was "How do you get acquainted with a new codebase? So given that you're changing projects so often, what are some of the tips and tricks for ways that you've learned to then quickly get up to speed with a new codebase?" Because, frankly, that is one of the thoughtbot superpowers is that we are really good at onboarding each other and then also getting up to speed with a new team, and their processes, and their codebase. So I have a couple of ideas, and then I'd love to hear some of your thoughts as well. So I'll dive in with a couple. So the first one, this one's frankly my favorite. Like day one, if there's a team where I'm joining and they have someone that can walk me through the application from the users' perspective, maybe it's someone that's in sales, or maybe it's someone on the product team, maybe it's a recording that they've already done for other people, but that's my first and favorite way to get to know an application. I really want to know what are users experience as they're going through this app? That will help me focus on the more critical areas of the application based on usage. So if that's available, that's fabulous. I'm also going to tailor a lot of this more to like a Rails app since that's typically the type of project that I'm onboarding to. So the other types of questions that I like to find answers to are just like, what's my top-level structure? Like to look through the app and see how are things organized? Chris, you've mentioned in a previous episode where you have your client structure that then highlights all the third-party clients that you're working with. Are we using engines in the app? Is there anything that seems a bit more unique to that application that I'm going to want to brush up on or look into? What's the test coverage like? Do they have something that's already highlighting how much test coverage they have? If not, is there something that then I can run locally that will then show me that test coverage? I also really like to look at the routes file. That's one of my other favorite places because that also is very similar to getting an overview of the product. I get to see more from the user perspective. What are the common resources that people are going to, and what are the domain topics that I'm working with in this new application? I've got a couple more, but I'm going to pause there and see how you get acquainted with a new app. CHRIS: Well, unsurprisingly, I agree with all of those. We're still searching for that dare to disagree beyond Pop-Tarts and IPAs situation. To reiterate or to emphasize some of the points you made, the sales demo thing? I absolutely love that one because, yes, absolutely. What's the most customer-centric point of view that I can have? Can I then login to a staging version of the site so I can poke around and hopefully not break anything or move real money or anything like that? But understanding why is this thing, not in code, but in actual practical, observable, intractable software? Beyond that, your point about the routes, absolutely, that's one of my go-to's, although the routes there often is so much in the routes, and it's like some of those may actually be unused. So a corollary to the routes where available if there's an APM tool like Scout, or New Relic, or something like that, taking a look at that and seeing what are the heavily trafficked endpoints within this app? I like to think about it as the entry points into this codebase. So the routes file enumerates all of them, but some of them matter, and some of them don't. And so, an APM tool can actually tell you which are the ones that are seeing a ton of traffic. That's a really interesting question for me. Similarly, if we're on Heroku, I might look is there a scheduler? And if so, what are the tasks that are running in the background? That's another entry point into the app. And so I like to think about it from that idea of entry points. If it's not on Heroku, and then there's some other system, like, I've used Cronic. I think it's Cronic, Whenever the Cron thing. Whenever, that's what it is, the Whenever gem that allows you to implement that, but it's in a file within the codebase, which as an aside, I really love that that's committed and expressive in the code. Then that's another interesting one to see. If it's more exotic than that, I may have to chase it down or ask someone, but I'll try and find what are all of the entry points and which are the ones that matter the most? I can drill down from there and see, okay, what code then supports these entry points into the application? I want to give an answer that also includes something like, oh, I do fancy static analysis in the codebase, and I do a churn versus complexity graph, and I start to...but I never do that, if we're being honest. The thing that I do is after that initial cursory scan of the landscape, I try and work on something that is relatively through the layers of the app, so not like, oh, I'll fix the text in a button. But like, give me something weird and ideally, let me pair with someone and then try and move through the layers of the app. So okay, here's our UI. We're rendering in this way. The controllers are integrated in this way, et cetera. This is our database. Try and get through all the layers if possible to try and get as holistic of a view of how the application works. The other thing that I think is really interesting about what you just said is you're like, I'm going to give some answers that are somewhat specific to a Rails app. And that totally makes sense to me because I know how to answer this in the context of a Rails app because those organizational patterns are so useful that I can hop into different Rails apps. And I've certainly seen ones that I'm like, this is odd and unfamiliar to me, but most of them are so much more discoverable because of that consistency. Whereas I have worked on a number of React apps, and every single one I come into, I'm like, okay, wait, what are we doing? How are we doing state management? What's the routing like? Are we server-side rendering, are we not? And it is a thing that...I see that community really moving in the direction of finding the meta frameworks that stitch the pieces together and provide more organizational structure and answer more of the questions out of the box. But it continues to be something that I absolutely love about Rails is that Rails answers so many of the questions for me. New people joining the team are like, oh, it's a Rails app, cool. I know how to Rails, and we get to run with that. And so that's more of a pitch for Rails than an answer to the question, but it is a thing that I felt in answering this question. [laughs] But yeah, those are some thoughts. But interested, it sounds like you had some more as well. I would love to hear what else was in your mind when you were thinking about this. STEPH: I do. And I want to highlight you said some really wonderful things. One that really stuck out to me that I had not considered is using Scout APM to look at heavily-trafficked endpoints. I have that on my list in regards as something that I want to know what's my error tracking, observability. Like, if I break something or if you give me a bug ticket to work on, what am I going to use? How am I going to understand what's going wrong? But I hadn't thought of it in terms of seeing which endpoints are heavily used. So I really liked that one. I also liked how you highlighted that you wish you'd do something fancy around doing a churn versus complexity kind of graph because I thought of that too. I was like, oh, that would be such a nice answer. But the truth is I also don't do that. I think it's all those things. I think it would be fun to make it easy. So I do that with new applications. But I agree; I typically more just dive in like, hey, give me a ticket. Let me go from there. I might do some simple command-line checking. So, for example, if I want to look through app models, let's find out which model is the largest. I may look for that to see do we have a God object or something like that? So I may look there. I just want to know how long are some of these files? But I also don't use a particular tool for that churn versus complexity. CHRIS: I think you hit the nail on the head with like, I wish that were easier or more in our toolset. But here on The Bike Shed, we tell the truth. And that is aspirational code flexing that we do not yet have. But I agree, that would be a really nice way to explore exactly what you're describing of, like, who are the God models? I'll definitely do that check, but not some of the more subtle and sophisticated show me the change over time of all these...like nah, that's not what I'm doing, much as I would like to be able to answer that way. STEPH: But it also feels like one of those areas like, it would be nice, but I would be intrigued to see how much I use that. That might be a nice anecdote to have. But I find the diving into the codebase to be more fruitful because I guess it depends on what I'm really looking at. Am I looking to see how complicated of a codebase this is? Because then I need to give more of a high-level review to someone to say how long I think it's going to take for me to work on a particular feature or before I'm joining a team, like, who do I think are good teammates that would then enjoy working on this application? That feels like a very different question to me versus the I'm already part of the team. I'm here. We're going to have complexity and churn. So I can just learn some of that over time. I don't have to know that upfront. Although it may be nice to just know at a high level, say like, okay, if I pick up a ticket, and then I look at that churn and complexity, to be like, okay, my ticket falls right smack-dab in the middle of that. So it's going to be a fun first week. That could be a fun fact. But otherwise, I'm not sure. I mean, yeah, I'd be intrigued to see how much it helps me. One other place that I do browse is I go to the gem file. I'm just always curious, what do people have in their tool bag? I want to see are there any gems that have been pulled in that are helping the team process some deprecated behavior? So something that's been pulled out of Rails but then pulled into a separate gem. So then that way, they don't have to upgrade just yet, or they can upgrade but then still keep some of that existing old deprecated behavior. That kind of stuff is interesting to me. And also, you called it earlier pairing. That's my other favorite way. I want to hear how people talk about the codebase, how they navigate. What are they frustrated by? What brings them joy? All of that is really helpful too. I think that covers all the ways that I immediately will go to when getting acquainted with a new codebase. CHRIS: I think that covers most of what I have in mind, although the question is framed in an interesting way that I think really speaks to the consultant mindset. How do I get acquainted with a new codebase? But if you take the question and flip it around sort of 180 degrees, I think the question can be reframed as how does an organization help people onboard into a codebase? And so everything we just described are like, here's what I do, here's how I would go about it, and pairing starts to get to collaboration. I think we've talked in a number of episodes about our thoughts on onboarding and being intentional with that, pairing people up. A lot of things we described it's like, it's ideal actually if the organization is pushing this. And you and I both worked as consultants for long enough that we're really in the mindset of like, all right, let's assume I'm just showing up. There's no one else there. They give me a laptop and no documentation and no other humans I'm allowed to talk to. How do I figure this out and get the next feature out to production? And ideally, it's something slightly better than that that we experience, but we're ready for whatever it is. Versus, most people are working within the context of an organization for a longer period of time. And most organizations should be thinking about it from the perspective of how do I help the new hires come into this codebase and become effective as quickly as possible? And so I think a lot of what we said can just be flipped around and said from the other way, like, pair them up, put them on a feature early, give them a walkthrough of the codebase, give them a sales-centric demo. Yeah, I feel equally about those things when said from the other side, but I do want to emphasize that this shouldn't be you're out there in the middle of the jungle with only a machete, and you got to figure out this codebase. Ideally, the organization is actually like, no, no, we'll help you. It's ours, so we know it. We can help you find the weird stuff. STEPH: That's a really nice distinction, though, because you're right; I hadn't really thought about this. I was thinking about this from more of the perspective of you're out in the jungle with a machete, minus we did mention pairing in there [laughs] and maybe a demo. I was approaching it more from you're isolated or more solo and then getting accustomed to the codebase versus if you have more people to lean on. But then that also makes me think of all the other processes that I didn't mention that I would include in that onboarding that you're speaking of, of like, how does this team work in terms of where do I push my code? What hooks are going to run? And then what do I wait for? How many people need to review my code? There are all those process-y questions that I think would ideally be included on the onboarding. But that has happened before, I mean, where we've joined projects, and it's been like, okay, good luck. Let us know if you need anything. And so then you do need those machete skills to then start hacking away. [laughs] CHRIS: We've been burned before. STEPH: They come in handy. [laughs] So when you are in that situation, and there's a comet that's coming to destroy earth, and there's a Rails application that is preventing this big doomsday, the question is, do you take astronauts and train them to be Rails experts, or do you take Rails developers and train them to be astronauts? I think that's the big question. CHRIS: What would Michael Bay do? STEPH: On that note, shall we wrap up? CHRIS: Let's wrap up. The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeeeee!!!!!!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

The Bike Shed
345: Fire Drill

The Bike Shed

Play Episode Listen Later Jul 12, 2022 49:22


Chris is getting ready to travel, and of course, Sagewell started the day with an incident, a situation, if you will... Steph talks books perfect for vacations and feels sufficiently scarred regarding still working with moving fixtures over to FactoryBot. 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. Back to Basics: Boolean Expressions (https://thoughtbot.com/blog/back-to-basics-booleans) Sarah Drasner tweet (https://twitter.com/sarah_edo/status/1538998936933122048) Become a Sponsor (https://thoughtbot.com/sponsorship) of The Bike Shed! Transcript: STEPH: All right, I am now officially recording as well. Let me make sure my microphone is in front of my face. Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Steph Viccari. CHRIS: And I'm Chris Toomey. STEPH: And together, we're here to share a bit of what we've learned along the way. So, hey, Chris, what's new in your world? CHRIS: What's new in my world? Today is an interesting day. We are recording on a Friday, which is not normal for us, was normal for a long time and then stopped, but now it's back to being normal. But it's the morning, which is confusing. Also, I am traveling this evening. I leave on a flight going to Europe. So I'm going to do a red-eye, that whole thing. So I got a lot to pack into today, literally packing being one of those things. And then this morning, because obviously, this is the way the world should play out, we started the day with an incident at Sagewell, a situation. Some code had gotten out there that was doing some stuff that we didn't want it to do. And so we had to sort of call in the dev team. And we all huddled together and tried to figure it out. Thankfully, it was a series of edge cases. It was sort of one of those perfect storms. So when this edge case happens in this context, then a bad thing could happen. Luckily, we were able to review the logs; nothing bad happened. While I'm unhappy that we had this situation play out... basically, it was a caching thing, just to throw that out there. Caching turns out to be very hard. And the particular way it played out could have manifested in behavior that would have been not good in our system, or an admin would have inadvertently done something that would have been incorrect. But on the positive side, we have an incident review process that we've been slowly incubating within the team. One of our team members introduced it to us, and then we've been using it on a few different cases. And it's really great to just have a structured process. I think it's one of those things that will grow over time. It's a very simple; what's the timeline of what happened? What's the story as to why it happened and why it wasn't caught earlier? What are the actions that we're going to take? And then what's the appendix? What's the data that we have around it? And so it's really great to just have that structure to work within. And then similarly, as far as I can tell, the first even observable instance of this behavior in our system was yesterday morning. We saw it, started to respond to it, saw one more. We were able to chase it down in the logs. Overall, the combination of the alerting that we have in Sentry and the way in which we respond to the alerting in Sentry, which I think is probably the most critical part. Datadog is our log metrics tool right now. So we're able to go through Datadog, and we have Lograge configured to add more detail to our log lines. And so we're able to see a very robust story of exactly what happened and ask the question, did anything actually bad happen? Or was it just possible that something bad could happen? And it turns out just possible. Nothing actually happened. We were able to determine that. We were even able to get a more detailed picture of who were all the users who potentially could have been impacted. Again, I don't think there was any impact. But all total, it was both a very stressful process, especially as I'm about to go on vacation. It's like, oh cool, start to the day where I'm trying to wrap up things, and instead, we're going to spend a couple of hours chasing down an incident. But that said, these things will happen. The way in which we were able to respond, the alerting and observability that we had in place make me feel good. STEPH: I like the incident structure that you just laid out. That sounds really nice in clarifying what happened when it happened in the logs. And the fact that you're able to go through and confirm if anything really bad happened or not is really nice. And I was also just debating this is one of those things, right? Right when you're about to go on vacation, that's when something's going to break. And that's like, is that good or bad? Is it good that I was here to take care of it right before, or is it bad? Because I'd really like to not be here to take care of it. [laughs] You may have mixed feelings. I have mixed feelings. CHRIS: I think I'm happy. Unsurprisingly, this exists in one of the most complex parts of our codebase. And it involves caching. And I remember when we introduced the caching, I looked at it, and I was like, hmm, we have a performance hotspot that involves us making a lot of requests to an external system. And so we thought about it a little bit, and we were like, well, if we do a little bit of caching here, we can actually reduce that down from seven calls down to one over external HTTP. And so okay, that seems to make sense. We had a pull request. We did a formal review. And even I looked at the pull request where this was introduced initially, and my comments on it were like, yep, this all looks good. Makes sense to me. But it's caching-related. So let's be very careful and look very closely at it and determine if there's anything, but it's so hard to know. And in fact, the code that actually was at play here was introduced a month ago. And interestingly, the observable side effect only occurred in the past two days, which we find very surprising. But again, it's this weird like, if A happens and then within a short period after that B happens...and so it's not quite a race condition. But it was something where a lot of stuff had to happen in a short span of time for this to actually manifest. And so, again, we were able to look through the logs and see all of the instances where it could have happened and then what did happen. Everything was fine, but yeah, it was interesting. I feel actually good to have seen it. And I think we've cleared everything up related to it and been very proactive in our response to it so that all feels good. And also, this is the sort of thing we've done this a few times now where we've had what I would call lesser incidents. There was no customer-facing impact to this. Similarly, previous incidents, we've had no or very minimal customer-facing impact. So at one point, we had a situation where we weren't processing our background jobs for a little while. So we eventually caught up and did everything we needed to. It just meant that something may not have happened in as timely a fashion as necessary. But there were no deep ramifications to that. But in each of those cases, we've pushed ourselves to go through the incident process to make sure that we're building the muscle as a team to like, actually, when the bad one comes, we want to be ready. We want to have done a couple of fire drills first. And so partly, I viewed this as that because again, there was smoke, but no fire is how we would describe it. STEPH: Nice. And that also makes sense to me how you were saying y'all introduced this about a month ago, but you were just now seeing that observable side effect. I feel like that's also how it goes. Like, you implement, especially with caching, some performance improvement, and then you immediately see that. And it's like, yay, this is wonderful. And then it's not til sometime passes that then you get that perfect storm of user interactions that then trigger some flow that you didn't consider or realize that could create an issue with that caching behavior. So yeah, that resonates. That seems right. All caching problems usually take about a month or two when you've just forgotten about what you've done. And then you have to go back in. CHRIS: Yep. Yep, yep, yep. So now we've done the obvious thing, which is we've removed every cache from the system whatsoever. There are no caches anymore because it turns out we just can't be trusted with caches in any form whatsoever. ActiveRecord, we turned off caching, Redis we threw it out. No, I'm kidding. We still have lots of caching in the app. But, man, caching is so hard. STEPH: I would love if that's in the project README where it says, "We can't be trusted with caches. No caches allowed." [laughs] CHRIS: Yeah, we have not gone all the way to forbid caching within the application. It's a trade-off. But this does have that you get those scars over time. You have that incident that happens, and then forever you're like, no, no, no, we can't do X. And I feel like I'm just a collection of those. Again, I think we've talked about this in previous episodes. But consulting for as long as I did, I saw a lot of stuff. And a lot of it was not great. And so I basically just look at everything, and I'm like, urgh, no, this will be hard to maintain. This is going to go wrong. That's going to blow up someday. And so, I'm having to work on trying to be a little more positive in my development work. But I do like that I have that inclination to be very cautious, be very pessimistic, assume the worst. I think it leads to safer code in general. There was actually a tweet by Sarah Drasner that was really wonderful. And it's basically a conversation between her and another developer. It's a pretend conversation. But it's like, "But why don't you like higher-order components?" And then it's Squints. "Well, in the summer of 2018, something bad happened, Takes a long drag of a cigarette. something very bad." It's just written so well and captures the ethos just perfectly. Like, sit down. Let me tell you a tale of the time in 2018. [laughs] So I'll include a link to that in the show notes because she actually wrote it so well too. It's got like scene direction within a tweet and really fantastic stuff. But yeah, we'll allow some caching to continue within the app. STEPH: That's amazing. So I was just thinking where you're talking about being more pessimistic versus optimistic. And there's an interesting nuance there for me because there's a difference in like if someone's pessimistic where if someone just brings up an idea and someone's like, "Nope, like, that's just not going to work," and they just always shoot it down, that level of being pessimistic is too much. And it's just going to prevent the team from having a collaborative and experimental environment. But always asking the question of like, well, what's the worst that could happen? And what are the things that we should mitigate for? And what are the things that are probably so unlikely that we should just wait and see if that happens and then address it? That feels like a really nice balance. So it's not just leaning into saying no to everything. But sure, let's consider all the really bad things that could happen, make a plan for those, but still move forward with trying things out. And I realized I do this in my own life, like when someone asks me a question around if there's something that we want to do that's a bit kind of risky. And the first thing I always think of is like, well, what's the worst that could happen? And I think that has confused people that I immediately go there because they think that I'm immediately saying no to the idea. And so I have to explain like, no, no, no. I'm very intrigued, very interested. I just have to think through what's the worst that can happen. And if I'm okay with that, then I feel better about accepting it. But my emotional state, I have to think through what's the worst and then go from there. CHRIS: Wow, it's a very bottom-up approach for your life planning there. [chuckles] STEPH: Yep, I think that's, you know, it's from being a developer for so long. It has impacted now how I make other decisions. Good or bad? Who knows? Yeah, it turns out being a developer has leaked into my personal life. I've got leaky abstractions over here. So, good or bad? Who knows? CHRIS: Leaky abstractions all the way down. Yeah, circling back to, like, I don't think I'm pessimistic per se. The way that I see this playing out often is there will be a discussion of an architectural approach, or there's a PR that goes up. And my reaction isn't no, or this has a known failure point; it is more of uh, this makes me uncomfortable. And it's that like; I can't even say exactly why, and that's what makes it so difficult. And I think this is a place that can be really complicated for communication, particularly between developers who have been around for a little bit longer and have done this sort of thing and have gathered these battle scars and developers who are a bit newer. Having that conversation and being like, um, I can't say exactly why. I can tell you some weird stories. I might not even remember the stories. Some of it just feeds into just like, does this code make me uncomfortable? Or does this code make me happy? And I tend towards wildly explicit code for these reasons. I want to make it as clear as possible and match as close as possible to the words that we're saying because I know that the bugs hide in the weird corners of our code. So I try and have as few corners. Make very rounded rooms of code is a weird analogy that doesn't play, but here we go. That's what I do on this show is I make weird analogies. Actually, we were working on some code that was dealing with branching conditional things. So we had a record which has a boolean value on it. So we've got true or false, and then we've got two states, and then we've gotten an enum with three states. So all total, we have six possible states. But as we were going through this conversation, I was pairing with another developer on the team. And I was like, something feels weird here. And I actually invoked the name of Joël Quenneville because much of the data structure thought that I had here I associate with work that Joël has done around Maybe and things like that. And then also, my suggestion was let's build a truth table because that seems like a fun way to manage this and look at it and see what's true. Because I know that there are spots on this two-by-three grid that should never happen. So let's name that and then put that in the code. We couldn't quite get it to map into the data type, like into that Boolean in the enum. Because it's possible to get into those states, but we never should. And therefore, we should alert and handle that and understand, like, how did this even happen? This should never happen. And so we ended up taking what was a larger method body with some of the logic in it and collapsing it down to very explicitly enumerate the branches of the conditional and then feed out to a method. Like, call a method that had a very explicit name to say, okay, if it's true and we're in this enum state, then it's bad, alert bad. And then the other case like, handle the good case. And I was very happy with what we refactored down to because this is another one of those very complex parts of our code. Critical infrastructure-y is how I would describe it. And so, in my mind, it was worth the I'm going to go with pathological refactoring that we got to there. But yes, I was channeling Joël in that moment. I'm very happy to have had many conversations with him that help me think through these things. STEPH: That's awesome. Yeah, those truth tables can be so helpful. There's a particular article that, of course, Joël has written that then describes how a truth table works and ways that you can implement it into your habits. It's called Back to Basics: Boolean Expressions. I will be sure to include a link in the show notes. CHRIS: But yeah, I think that summarizes my day and probably the next couple of days as I prepare for an adventure over to Europe and chat about developer spidey sense. But yeah, what's new in your world? STEPH: Yeah, that's a big day. There's a lot going on. Well, I actually want to circle back because you mentioned that you're packing and you're going on this trip. And I'm curious, do you have any books queued up for vacation? CHRIS: I do, yeah. I'm currently reading Elantris by Brandon Sanderson. Folks might be aware of his work from the highest-funded Kickstarter of all time, which was absurd. Did you see this happen? STEPH: I don't think so, uh-uh. CHRIS: He did this fun, cheeky little Kickstarter. The video was sort of a fake around...oh, it almost sounded like he might be retiring or something like that. And then he's like, JK, I wrote five new books. And so the Kickstarter was for those books with different tiered packages and whatnot. I think he got just the right viral coefficient going on. And apologies for the spoiler if anyone's not seen the video, but it's been out there for a while. So he wrote some books, and that's what the Kickstarter is for. You get some books. You sort of join a book club, and you'll get one a quarter. A million dollars seems like that will be a bunch for that. That'd be great. If he raised a million dollars, that'd be amazing. $40 million four-zero million dollars. [laughs] I'm just watching it play out in real-time as well. It just skyrocketed up. The video, I think, was structured just right. He got it onto the...it was on Reddit and Twitter and just bouncing around, and people were sharing it. And just everything about it seemed to go perfectly. And yes, the highest-funded Kickstarter of all time, I believe, certainly within the publishing world. But yeah, Brandon Sanderson, prolific author, and his stuff ends up just being kind of light and fun. And so I was reading Elantris for that. It's been a little bit slower to pick up than I would like. So I'm now in the latter half. I'm hoping it'll go a little bit more quickly and be...I'm just kind of looking for a fun read, some fantasy thing to go on an adventure. But as the next book, I downloaded a second one just to make sure I'm covered. I have a book by John Scalzi, who's a sci-fi, fantasy, more on the sci-fi end of the spectrum. And I've read some of his other stuff and enjoyed it. And this particular book has a very consistent set of reviews. I've read the reviews a few times. And everybody who reviews it is just like, "This isn't the greatest book I've ever read, but man was it a fun ride." Or "Yeah, no, best book? No. Fun book? Yes." And just like, "This book was a fun ride. This was great." And I was like, perfect. That is exactly what I'm looking for on a European vacation. The book is called The Kaiju Preservation Society, which also plays on monsters, Pacific Rim Godzilla. Kaiju, I think, is the word for that category of giant dinosaur-like monster. And so it's the Kaiju Preservation Society, which, I don't know, means some stuff, and I'm going to go on a fun adventure. So yeah, those are my books. STEPH: Nice. I've got one that I'm reading right now. It's called Clementine: The Life of Mrs. Winston Churchill, written by Sonia Purnell. And Sonia Purnell tends to focus on female historical figures. And so it's historical fiction, which is a sweet spot for me. The only thing I'm debating on is because I'm realizing as I'm reading through it, I'm questioning, okay, well, what's real and what's not? Because I don't want to be that person that's like, did you know? And then, I quote this fictional fact about somebody that was made up for the novel. [laughs] So I'm realizing that maybe historical fiction is fun, but then I'm having to fact-check all the things because then I'm just curious. I'm like, oh, did this really happen, or how did it go down? So it's been pretty good so far. But then it makes me wish that historical fiction novels had at the back of them they're like, these are all the events that were real versus some of the stuff that we fictionalized or added a little flair to. I'm in that interesting space. I also like how you highlighted that you chose a fun book. I was having a conversation with a colleague recently about downtime. And like, do you consume more tech during downtime? Like, are you actively looking for technical blog posts or technical books to read or podcasts, things like that? And I was like, I don't. My downtime is for fun. Like, I want it to be all the things that are not tech. Maybe some tech sneaks in there here and there, but for the most part, I definitely prioritize stuff that's fun over more technical content in my spare time, which has taken me a little while to not feel guilty about. Earlier in my career, I definitely felt like I should be crunching technical content all the time. And now I'm just like, nope, this is a job. I'm very thankful that I really enjoy my job, but it's still a job. CHRIS: It is an interesting aspect of the world that we work in where that's even a question. In my previous life as a mechanical engineer, the idea that I would go home and read about mechanical engineering...I could attend a conference, but I would do that for very particular reasons and not because, like, oh, it's fun. I'll go meet my friends. For me, this was a big reason that I moved into tech because I am one of those folks who will, like, I will probably watch a video about Remix in particular because that's my new thing that I like to play around with and think about. But it needs to be a particular shape of thing I've found. It needs to be exploratory, puzzle-y. Fun code, reading, learning work that I do needs to be separated from my work-work in a certain way. Otherwise, then it feels like work, then it is sort of a drudgery. But yeah, my brain just seems to really like the puzzle of programming and trying to build things. And being able to come into a world where people share as much as they do blogs and conference talks and all of that is utterly fantastic. But it is a double-edged sword because I 100% agree that the ability to disconnect to, like, work a nine-to-five and then go home at the end of the day. Yeah, go home, you know, because you remember when we went to an office and then we would go home afterwards? I have to commute every once in a while into the city and -- STEPH: You mean go downstairs or go to another room? That's what you mean? [laughs] CHRIS: I used to commute every day, and it took a lot of time. And now when I do it, I feel that so viscerally because I'm like, it's just a lot easier to just walk to my office in my house. But yes, I 100% I'm aligned to that like, yeah, no, you're done with work for the day, walk away. That's that. And learning a new technology or things like that, that's part of the job. There shouldn't be the expectation that that just happens. There's continuing education in every other field. It's like, oh, we'll pay for your master's degree so you can go learn a thing. That's the norm in every other...not in every other industry but many, many, many industries. And yet the nature of our world the accessibility of it is one of the most wonderful things about it. But it can be a double-edged sword in that if there are the expectations that, oh yeah, and then, of course, you're going to go home and have side projects and be learning things. Like, no, that is an unreasonable expectation, and we got to cut that off. But then again, I do do that. So I'm saying two things at the same time, and that's always complicated. STEPH: But I agree with what you're saying because you're basically respecting both sides. If people enjoy this as a hobby, more power to you.; that's great. This is what you enjoy doing. If you don't want to do this as a hobby and respect it as a job, then that's also great too. There can be both sides, and no side should feel guilty or judged for whichever path that they pursue. And I absolutely agree, if there are new skills that you need to learn for a job, then there should be time that's carved out during your work hours that then you get to focus on those new skills. It shouldn't be an expectation that then you're going to work all day and then spend your evening hours learning something else. And same for interviews; there shouldn't be a field that says, "Hey, what are your side projects?" Or at least that should not be an important part of the interview. There should be an alternative to be like, "Or what work code do you want to talk about?" Or something else that's more in that nine-to-five window that you want to talk about. That way, there's a balance between like, sure, if you have something that you want to talk about on the side, great, but if not, then let's focus on something that you've done during your actual work hours because that's more realistic. CHRIS: I do think there's an interesting aspect at play because the world of development moves so rapidly and because it's constantly changing. And to frame it differently, I don't think we've got this thing figured out. And so many people lament how quickly it changes and that there's a new framework every other week. And there's a bit of churn that is perhaps unnecessary. But at the same time, I do not feel like as a community, as a working population, that we're like, yeah, got it, crushed it. We know how to make great software, no question about it. It's going to be awesome. We're going to be able to maintain it for forever, don't even worry about it. New feature? We can get that in there. They're actually still pretty rare. So we need to be learning, and evolving, and exploring new techniques. I think the amount of thinking is probably good mostly in the development world. But organizations have to make space for that with their teams. And thoughtbot obviously does that with investment days. That's just such a wonderful structure that embraces that reality and also brings happiness, and it's just a pleasant way to work. And frankly, my team does not have that right now. We do the crispy Brussels snack hour, which also now has a corresponding crispy Brussels work lunch, which is one week we think about it, and the next week we do the thing. We're trying to make space for that. But even that is still more intentional and purposeful and less exploratory and learning. And so it's an interesting trade-off. I deeply believe in this thing, and also, the team that I'm leading isn't doing it right now. Granted, we're an early-stage startup. We got to build a bunch of stuff. I think that's fine for right now. But it is a thing that...again, I'm saying two things at the same time, always fun. STEPH: Well, and there might be a nice incremental approach to this as well. So thoughtbot has the entire day, and maybe it's less than a full day. So perhaps it's just there's an hour or two hours or something like that where you start to introduce some of that self-improvement time and then blossom out from there. Because yeah, I understand that not all teams may feel like they have the space for that. But then I agree with everything else you said that it really does improve team morale and gives people a space to then be able to get to explore some of those questions that they had earlier. So then they don't feel like they have to then dedicate some weekend time or off hours' time to then look into a question. And I admit, I'm totally guilty too. I am that person that then I've worked extra hours, but it's because, like you said, if there's a puzzle that my brain is stuck on and I just feel the need to get through it. But then I look at that as am I doing this because I want to? Yes. Okay, then as long as I'm happy and I don't feel like this is increasing any concern around burnout, then I don't worry about it. MIDROLL 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 you 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 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 enables 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 and includes 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! Circling back to your original question about what's going on in my world, and you mentioned scarring earlier. I feel sufficiently scarred [laughs] in regards to still working with moving fixtures over to FactoryBot. This week has really confirmed that fixtures don't trigger a lot of the callbacks, the model callbacks that exist. And so this really means that you can just create bad data that your application doesn't actually allow your application to create. So there are tests that are exercising behavior that should never exist. And then porting that over to FactoryBot then highlights that because then as soon as I move that record over and then try to create it or do something with it, then the app, the test, do the right thing and let me know saying no, no, no, we've added validations. You can't do that anymore. That has been grinding my gears in terms of trying to then translate. Because then I have to really dive into the code to understand it. And the goal here is to stay as high level as possible and not have to dive in too much. But then that means that I do have to dive in and understand more. So this has frankly just been one of those times in my career where you just kind of have to slog through the work. It's important work to be done. It'll be great once it's done. But it's a painful process. And the best way that I've found to make it more enjoyable is to be in heavy communication with Joël, who's on the project with me, just so if we get stuck on something, then we can chat with each other. And then also there's one file that's particularly gnarly. And so we moved over one test. We were successful, and which felt great because then we could at least document like, okay, when we come back to this, at least we have one example that highlights the wonkiness that we ran into. But we've decided, okay, we're done with that file. We're going to take a break. There's a lot there, but we're going to move on and give ourselves a break and do some of the easier ones, and then we'll circle back to the harder one. Which was, I think, just a bit of bad luck in terms of, like, as we're going down the list, that happened to be like the gnarliest one, and it was like the first one that Joël picked up. And so I'm going through a couple of files, and Joël is like, "What? [laughs] How are you making progress?" And we realize it's just because that file, in particular, is very hard to find all the mystery guests and then to move everything over. Finding a positive note through all of the cruft, I will say this is helping with some of my code sleuthing skills. So as I am running into these problems and then looking for mystery guests, I'm noticing ways that I can then, as quickly as possible, try to triage and identify as to why one test doesn't match another test. Some of it is more specific to the application setup, so it won't be as applicable to future projects. But then some other areas have been really helpful. Like, I'm using caller a lot more to understand, like, I know this is getting called, but I don't know who's calling you. So I can put in a line that basically outputs like, show me your stack traces to how you got here. So that's been really nice as well. So it has improved some of my code sleuthing skills and also my spidey sense in terms of it's typically mystery guests. Like when a test isn't passing, it's because fixtures are creating extra data that are getting pulled in when there are queries that are being run. But they're not explicitly referenced in the test setup itself. So that's typically then where I start is looking for what record looks relevant to this test that I haven't pulled over to my test setup. CHRIS: I appreciate you finding the silver lining, the positive bit of this. Because as you're describing, the work that you're doing sounds like I think you use the word slog, which seems like a very accurate term. But sometimes we have to do that sometimes for a variety of reasons. We end up either having to introduce new code or fix old code, but this is sometimes the work. And this is something that I think you and I share about this show is we get to show all sides of the work. And the work can be glamorous and new. And oh, I've got this greenfield app that I'm building, and it's wonderful. Look at the architecture. And I know in the moment that I'm building someone else's legacy code three years from now. [laughs] And so telling the other side of the story and providing that rounded point of view, because like, yeah, this is all part of it. Again, I don't believe that this is a solved problem, building robust software that we can maintain. And so yeah, you're doing the good work in there. And I thank you for sharing it with us. STEPH: Thanks. Just don't use fixtures in your test, I beg of you. Please don't do that to the legacy code that you're writing for future developers. [laughs] That is my one request. CHRIS: And I will maybe add on to that, sparingly use callbacks. Maybe don't use them at all, and certainly don't use the combination because, my goodness, that'll lead you into some fun times. But yeah, just two small recommendations there. STEPH: Oh, there's something else I wanted to share. I saw that Slack added a new audio feature that allows you to record the pronunciation of your name, which is the feature that I was so excited about when we added it to our internal tool called Hub at thoughtbot. And now Slack has it on their profile so that way you can upload the pronunciation. And then anyone looking at your profile can then listen to how to pronounce your name. There are a couple of other features that they released, I think just in June, so about a month ago from the recording of today. [laughs] That's weird to say, but here we are. So I'll include a link in the show notes so folks can see that feature in addition to others, but I'm super excited. CHRIS: Oh, that is nice. I also like all right, so Slack now has it. Hub now has it. But I don't have access to Hub anymore. And I don't have access to every Slack in the world yet. But here's my suggestion. All right, everybody, stick with me here. I want you to own a domain. I want you to have a personal site on it. And I want the personal site to include the pronunciation of your name. I get that that's a big ask. And I get that there are other platforms that are calling to you, and you may be writing on those. But you know what? Just stand up a little site, just a little place on the internet that you own. And if it includes the pronunciation of your name, I will be forever grateful. STEPH: I like this idea. I initially was taking your idea and immediately running with it as you were speaking it because then I wondered if everyone had their own YouTube channel. But I don't know how hard it is to create a YouTube channel. I am not a YouTube channeler, so I don't know what that looks like. [laughs] But not everybody will know how to purchase a domain. So that might be another approach. CHRIS: I think it's pretty easy to do a YouTube channel. I'm conflating a couple of things. This is my basket of beliefs about people on the internet, but I kind of think everybody should own their own little slice of the internet. And so totally, YouTube is a place where the people make some stuff, make videos, put them on YouTube, absolutely. But ideally, you own something. I see a lot of people that are on YouTube, and that's it, and so their entire audience lives on YouTube. And if YouTube someday decides to change or remove them or say Medium as an example, Medium actually, I think, does a more interesting version of this where your identity kind of gets subsumed into Medium. And I really think everybody should just have their own little, tiny slice of the internet that's there. It has their name that they own that no platform can decide; hey, we've shifted, and now your stuff is gone. Cool URIs don't change as they say, and that's what I want. And then yeah, if you can have the pronunciation of your name on there, that's extra nice. Although I say that, and I don't know that I would do it because my name feels very obvious. One day someone was like, "Oh, how do you pronounce your last name?" I forget if I actually replied with the pronunciation. Or if I was like, "I need to know what options you're considering. I'm so interested because I've really only got the one." Maybe I'm anchored. Maybe I'm biased. [chuckles] I've been doing this for a while. But I really cannot think of another pronunciation of my name. STEPH: You might hear another one that you really like, and you need to pivot. CHRIS: Oh gosh. STEPH: That's the point where you start pronouncing your name differently. CHRIS: Wow, that would be a lot. And then, I could have a change log on my personal site where people can see this is the pronunciation, and this is what the pronunciation used to be. STEPH: [laughs] I like this idea. I also like this idea that everybody has their own slice of internet land. I like this encouragement that you're providing for everyone. On a slightly different note, there's a blog post that I'm really excited to talk about. It's written by Eric Bailey, who's a former thoughtboter. It's called The Optics of Pair Programming. And given how much pair programming that I'm doing, especially with Joël on the current project, it was a really wonderful read. And it also helped me think about pairing from a different perspective because we do have a very strong pairing culture at thoughtbot. So there's a lot of nuance, especially social nuances that can go along with when you invite someone to pair with you that I had not considered until I read this wonderful post by Eric. And we'll be sure to include a link in the show notes. But to provide an overview, essentially, Eric shares that given coming from thoughtbot where we do have a very open approach to pairing where pairing sessions are voluntary and then also last as long as the problem will last...but then when you're at a new company, you could experience pushback if you're inviting someone to pair and then to consider why that pushback may exist. And some of the high-level areas that Eric highlighted are power dynamics, assessment, privacy, and learning styles. So to dive into each of some of those, there's a power dynamics of it's important to consider who's offering to pair. So if I've joined a team as a consultant, there may be a power dynamic there that someone is feeling where their team is paying for my time. So they may feel like they can't say no if I offered to pair. They feel like they need to say yes to the invitation, even if they don't really want to. Or probably a more classic example would be like, what if your boss wants to pair or someone that's just more senior than you? Then it could leave you feeling like, well, I can't say no to this person, can I? Which yes, you totally can say no to that person, but it may leave you in a place where you feel like you can't. And so, it puts you in this sort of uncomfortable and powerless position. The other one is assessment, so offering to pair with someone could feel like you are implying that you want to assess their skills or that you're implying that they're not up to the task and therefore they need your help. So then that could also place someone in an uncomfortable position. There's also privacy. So someone who isn't confident may not want someone to observe their behavior or observe how they're working. It could make them feel really anxious, which then I love that Eric points this out. Ironically, pairing is really good at addressing that lack of confidence because then you get to see how other people work through their problems or how they think, or they may also have some anxiety. Or it just helps you become more comfortable in talking and thinking through with other people. So that one is a tough one where it's hard to get over that initial hurdle. But actually, the more you pair, then the less anxious you'll feel when you pair. And then there's also learning styles because pairing really involves a lot of deep thinking but in our personal time. And it can be hard to balance both of those, and it's just not as effective for some people. So I know that even as much as I really enjoy pairing, I just need to sit with code on my own sometimes. I need to think about it. I need to run it; I need to look at it. So it's really nice to talk with someone. But then I also need that alone time to then just think through it on my own because I can't have that same deep focus if I'm also worried about how the other person is experiencing that session because then my mental energy is going towards them. So that covers a number of the social nuances that can be included or running through someone's mind when you extend an invitation to them to pair. And it really resonated with me the areas that Eric highlights in this blog post. He also talks about a couple of strategies, which I'd love to dive into as well. But I'm going to pause here and see what thoughts you have. CHRIS: Yeah, I love this post. And it got me thinking about pairing and the broader human backdrop of all of the processes and workflows that we have. Everything he highlighted about pairing feels true. Although similar to you and to Eric, I've worked in a context where pairing was a very natural, very regular part of the work and sort of from the very top-down. And so everyone pairing between developers of any different level or developers and designers or really anyone in the...it was just such a part of how we worked that no one really questioned it or at least not after the first couple of weeks. I imagine joining thoughtbot those first weeks; you're like, oh God. As I shared, I think in the previous episode that we recorded, my pairing interview was with Joe Ferris, the CTO of thoughtbot, [laughs] writing a book about good and bad code. And I was like, I don't know what anything is here but very quickly getting over that hurdle. And having that normalizing experience was actually really great, and then have been comfortable with it since. But the idea that there are so many different social dynamics at play feels true. And then as I think about other things, like stand-up is one that I think of as this very simple this is a way to communicate where we're at. And where necessary or where useful, allow people to interject or step in to say, "Oh, let me help you get unblocked there or whatever it is." But so often, I see stand-up being a ritual about demonstrating that you are, in fact, doing work, which is like, here's what I did yesterday. I don't know if it's useful. Then mention that you're working on this project. But the enumeration of look, obviously, work was done by me. You can see it; here are the receipts. It's very much this social dynamic at play. And retro is another one where like, if retro is very much owned by one voice and not a place that change actually happens where people feel safe airing their opinions or their concerns, then it's going to be a terrible experience. But if you can structure it and enforce that it is a space that we can have a conversation, that everyone's voice is welcome and that real change happens as a result of, then it's a magical tool for making sure we're doing the right things. But always behind these are the people, and feelings, and the psychology at play. And so this was just such an interesting post to read and ruminate on that a little bit more. STEPH: Yeah, I agree, especially with a comment that you made about those daily syncs where I really just want to focus on today and what you have that you're blocked on. So it's a really nice update in case there are any cross-collaboration opportunities. That's really what I'm looking for in a daily update. And so I appreciate when people don't go through a laundry list of what they did yesterday because it's like, that's great. But then, like you said, it's just like you're trying to prove here's what I've done, and I trust you; you're working. So just let me know what you're doing today, friend. So Eric does a wonderful job of also including some strategies for ways that then you can address some of these concerns and then how there may be some extra anxiety that's increased when you're inviting somebody to pair. There are some wonderful strategies. I'll let folks read through the blog post itself. There are a couple in particular that came to mind for me because I was then self-assessing how do I tend to approach pairing with someone? And some ways that I want them to feel very comfortable with that experience. And there's a couple. There's one where I recognize that I need to build trust with each person. I can't just go on to a team and expect everyone to know that I have good intentions and that I'm going to do my best to be a fun, helpful pairing partner, and that it's not a zone of judgment. And that has to be cultivated with each person. Because especially as a consultant, if I'm joining a team, the people who hired me are not necessarily the people that I'm working with. It's someone that's probably in leadership or management that has then brought on thoughtbot. And so then the people that I'm working with they don't know me, and they don't know what my pairing style is going to be. So looking for ways to build trust with each person and then also inviting them or asking for help myself. So there's a bit of vulnerability that has to be shown to build trust with someone to say," Hey, I'm stuck on a problem. I would love a second set of eyes. Would you be willing to help me out with this?" So then that way, they're coming in to help me initially versus I'm going in and saying, "Hey, can I help you?" I have found that to be an effective strategy. And there's one that I do really want to talk about, and that's not everyone is going to pair well together. Like, you may find someone who always leaves you feeling just stressed or demoralized. And while it's important to consider your role and why that's true, that does not mean it's your fault and necessarily your problem to fix. So similar to having to manage up, you may need to coach the person that you're pairing with in ways that help you feel comfortable pairing. But if they don't listen to your requests and implement any of that feedback, then just don't pair with that person. That is a very fine option to recognize people that are not receptive to your needs and, therefore, not someone that you need to then force into being a great pairing buddy. And I emphasize that last one because it took me a little while to become comfortable with that and accepting that it wasn't my fault that I wasn't having a great pairing session with people. Similar to when I'm learning from someone that if someone is explaining something to me and they're making me feel inadequate while they're explaining it to me, that's not necessarily my fault. Like, I used to internalize that as like, oh, I just can't get this. But I am now a very staunch believer in if you can't explain it to me in a way that I understand, then that's probably more on you than on me. And that has also taken me time to just really accept and embrace. But once you do, it is so freeing to realize that if someone's explaining a concept and you're still not getting it, it's like, hey, how can we try harder together versus you just making me try harder? CHRIS: I like that right there of like, if I don't understand this, it may actually be you, not me, or something to that effect. Let's get that on a bumper sticker and put that in The Bike Shed store so that everybody can buy it and put it on their cars or at least just us. But yeah, that starting from the bottom sometimes it's just not going to work great. There are even...I think what you're describing sounds a little more complicated, individuals who are personally not great at communicating or pairing or things like that. And that's going to happen. We're going to run into folks that...pairing is communication. That's just the core of it, and some folks, that may not be their strongest suit. But I think there's another category of just like different working styles. And whereas I might...judge is such a heavy word, but I'm going to use it. I might judge someone who is not doing a great job at communicating to someone else, or understanding their point of view, or striving to do that, or taking feedback. Like, those are not great things. Whereas there may just be two different development styles or backgrounds, or there are other reasons that actually they may be not an ideal fit. That said, I have definitely found that in almost every variation of pairing, I've seen work at some point. Like, when I was very early on in my career pairing with folks that are very senior, I didn't get most of it, but I got some stuff. And then folks that are very much on the same level or folks that have a deep knowledge in framework, code base language, whatever and folks that are new to it but have a different set of experiences. Basically, every version of that, I found that pairing is actually an incredibly powerful technique for knowledge sharing, for collaboration, for all of that. So although there are rare cases where there might be some misalignment, in general, I think pairing can work. I do think you hit on something earlier of there are certain folks that are more private thinkers, is how I would describe it, where thinking out loud is complicated for them. I'm very much someone who talks. That's how I figure out what I think is I say stuff. And I'm like, oh, I agree with what I just said. That's good. But I find I actually struggle. There's something I think of...maybe I'm just a loudmouth is what I'm hearing as I say it, but that is how I process things. Other folks, that is not true. Other folks, it's quite internal, and actually trying to vocalize that or trying to share the thought process as they're going may be uncomfortable. And I think that's perfectly reasonable and something that we should recognize and make space for. And so pairing should not be forced upon a team or an individual because there are just different mindsets, different ways of thinking that we need to account for. But again, the vast majority of cases...I've seen plenty of cases where it's someone's like, "I don't like to pair. That's not my thing." And it's actually that they've had bad experiences. And then when they find a space that feels safe or they see the pattern demonstrated in a way that is collegial, and useful, and friendly, then they're like, oh, actually, I thought I didn't like pairing. I thought I didn't like retro. I thought I didn't like stand-up. But actually, all of these things can be good. STEPH: Yeah, absolutely. It's a skill like anything else. You need to see value in it. And if you haven't seen value in it yet or if it's always made you anxious and uncomfortable, then it's something that you're going to avoid as much as possible until someone can provide a valuable, positive experience around how it can go. I'm going to pull back the curtains just a little bit on our recording and share because you've mentioned that you are very much you think out loud, and that's how you decide that you agree with yourself. And I think already at least twice while we've been recording this episode, I have started to say something, and I'm like, no, wait, I don't agree with that and have backed myself up. CHRIS: [laughs] STEPH: And I'm like, no, I just thought through it; I'm going to cancel it out, [laughs] and then moved in a different direction. So I, too, seem to be someone that I start to say things, and I'm like, oh, wait, I don't actually agree with what I just said [laughs], so let's remove that. CHRIS: Yep. You've described it as Michael Scott-ing on a handful of different episodes or maybe things that were cut from episodes. But where you start a sentence and then you're like, I don't know where I was going to end up there. I hoped I'd figure it out by the end, but then I did not get there. And yeah, I think we've all experienced that at various times. STEPH: That's some of my favorite advice from you is where you've been like, just lean into it, just see where it goes. Finish it out. We can always take it out later. [laughs] Because I stop myself because I immediately start editing what I'm trying to say and you're like, "No, no, just finish it, and then we'll see what happens." That's been fun. CHRIS: This is how you find out what you think. You say it out loud, and then you're like, never mind. That was ridic – STEPH: [laughs] CHRIS: I do. Actually, now I'm thinking back, and I have plenty of those where I'll say a thing, and I'm like, nope, never mind, send that one back. [chuckles] As an aside, so we do this thing where we host a podcast, and we get to talk. But we're both now describing the pattern where we'll start to say something, and we'll be like no, no, no, actually, not that. And I think, dear listeners out there, you probably don't hear any of this, the vast majority of it, because we have wonderful editors behind the scenes, Thom Obarski for many years, and now Mandy Moore, who's been with us for a while. And so once again, thank you so much to the editor team that allows us to, I think, again, feel safe in this conversation that we can say whatever feels true and then know that we'll be able to switch that around. So thank you so much to the editors who help us out and make us sound better than we are. STEPH: Yeah, that has made a big difference in my capabilities to podcast. If we were doing this live, ooh goodness, this might be a whole different, weird show. [laughs] CHRIS: I mean, the same is true for code, right? I deeply value the ability to make an absolute mess in my local editor and have nine different commits that eventually I throw two out. And then I revert that file, and then eventually, the PR that I put up that's my Instagram selfie. That's like, I carefully curated this, but what's behind the scenes it's just a pile of trash. So yeah, the ability to separate the creation and the editing that's a meaningful thing to have in life. STEPH: Oh, I can't unsee that now. [laughs] A pull request is now the equivalent of that curated Instagram selfie. That is beautiful. [laughs] CHRIS: To be clear, I don't think I've ever taken an Instagram selfie. But I get the idea, and I felt like it was an analogy that would work. Again, I try out analogies on this show, and many of them do not stick. But I think that one is all right. STEPH: It might even go back to pairing because then you've got help in taking that picture. So hey, you're making a mess with somebody until you get that right perfect thing, and then you push it up for the world to see. So safe spaces for all the activities, I think that's the takeaway. On that note, shall we wrap up? CHRIS: Let's wrap up. The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

The Bike Shed
344: Spinner Armageddon

The Bike Shed

Play Episode Listen Later Jun 28, 2022 38:50


Steph has an update and a question wrapped into one about the work that is being done to migrate the Test::Unit test over to RSpec. Chris got to do something exciting this week using dry-monads. Success or failure? This episode is brought to you by BuildPulse (https://buildpulse.io/bikeshed). Start your 14-day free trial of BuildPulse today. Bartender (https://www.macbartender.com/) dry-rb - dry-monads v1.0 - Pattern matching (https://dry-rb.org/gems/dry-monads/1.0/pattern-matching/) alfred-workflows (https://github.com/tupleapp/alfred-workflows/blob/master/scripts/online_users.rb) Raycast (https://www.raycast.com/) ruby-science (https://github.com/thoughtbot/ruby-science) Inertia.js (https://inertiajs.com/) Remix (https://remix.run/) Become a Sponsor (https://thoughtbot.com/sponsorship) of The Bike Shed! Transcript: AD: Flaky tests take the joy out of programming. You push up some code, wait for the tests to run, and the build fails because of a test that has nothing to do with your change. So you click rebuild, and you wait. Again. And you hope you're lucky enough to get a passing build this time. Flaky tests slow everyone down, break your flow, and make things downright miserable. In a perfect world, tests would only break if there's a legitimate problem that would impact production. They'd fail immediately and consistently, not intermittently. But the world's not perfect, and flaky tests will happen, and you don't have time to fix all of them today. So how do you know where to start? BuildPulse automatically detects and tracks your team's flaky tests. Better still, it pinpoints the ones that are disrupting your team the most. With this list of top offenders, you'll know exactly where to focus your effort for maximum impact on making your builds more stable. In fact, the team at Codecademy was able to identify their flakiest tests with BuildPulse in just a few days. By focusing on those tests first, they reduced their flaky builds by more than 68% in less than a month! And you can do the same because BuildPulse integrates with the tools you're already using. It supports all of the major CI systems, including CircleCI, GitHub Actions, Jenkins, and others. And it analyzes test results for all popular test frameworks and programming languages, like RSpec, Jest, Go, pytest, PHPUnit, and more. So stop letting flaky tests slow you down. Start your 14-day free trial of BuildPulse today. To learn more, visit buildpulse.io/bikeshed. That's buildpulse.io/bikeshed. STEPH: What type of bird is the strongest bird? CHRIS: I don't know. STEPH: A crane. [laughter] STEPH: You're welcome. And on that note, shall we wrap up? CHRIS: Let's wrap up. [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 Chris Toomey. STEPH: And I'm Steph Viccari. CHRIS: And together, we're here to share a bit of what we've learned along the way. So, Steph, what's new in your world? STEPH: Hey, Chris, I saw a good movie I'd like to tell you about. It was just over the weekend. It's called The Duke, and it's based on a real story. I should ask, have you seen it? Have you heard of this movie called The Duke? CHRIS: I don't think so. STEPH: Okay, cool. It's a true story, and it's based on an individual named Kempton Bunton who then stole a particular portrait, a Goya portrait; if you know your artist, I do not. But he stole a Goya portrait and then essentially held at ransom because he was a big advocate that the BBC News channel should be free for people that are living on a pension or that are war veterans because then they're not able to afford that fee. But then, if you take the BBC channel away from them, it disconnects them from society. And it's a very good movie. I highly recommend it. So I really enjoyed watching that over the weekend. CHRIS: All right. Excellent recommendation. We will, of course, add that to the show notes mostly so that I can find it again later. STEPH: On a more technical note, I have a small update, or it's more of a question. It's an update and a question wrapped into one about the work that is being done to migrate the Test::Unit test over to RSpec. This has been quite a journey that Joël and I have been on for a while now. And we're making progress, but we're realizing that we're spending like 95% of our time in the test setup and porting that over, specifically because we're mapping fixture data over to FactoryBot, and we're just realizing that's really painful. It's taking up a lot of time to do that. And initially, when I realized we were just doing that, we hadn't even really talked about it, but we were moving it over to FactoryBot. I was like, oh, cool. We'll get to delete all these fixtures because there are around 208 files of them. And so that felt like a really good additional accomplishment to migrating the test over. But now that we realize how much time we're spending migrating the data over for that test setup, we've reevaluated, and I shared with Joël in the Slack channel. I was like, crap. I was like, I have a bad idea, and I can't not say it now because it's crossed my mind. And my bad idea was what if we stopped porting over fixtures to FactoryBot and then we just added the fixtures to a directory that RSpec would look so then we can rely on those fixtures? And then that way, we're literally then ideally just copying over from Test::Unit over to RSpec. But it does mean a couple of things. Well, one, it means that we're now running those fixtures at the beginning of RSpec test. We're introducing another pattern of where these tests are already using FactoryBot, but now they have fixtures at the top, and then we won't get to delete the fixtures. So we had a conversation around how to manage and mitigate some of those concerns. And we're still in that exploratory. We're going to test it out and see if this really speeds us up referencing the fixtures. The question that's wrapped up in this is there's something different between how fixtures generate data and how factories generate data. So I've run into this a couple of times now where I moved data over to just call a factory. But then I was hitting these callbacks or after-save-hooks or weird things that were then preventing me from creating the record, even though fixtures was creating them just fine. And then Joël pointed out today that he was running into something similar where there were private methods that were getting called. And there were all sorts of additional code that was getting run with factories versus fixtures. And I don't have an answer. Like, I haven't looked into this. And it's frankly intentional because I was trying hard to not dive into understanding the mechanics. We really want to get through this. But now I'm starting to ponder a little more as to what is different with fixtures and factories? And I liked that factories is running these callbacks; that feels correct. But I'm surprised that fixtures doesn't, or at least that's the experience that I'm having. So there's some funkiness there that I'd like to explore. I'll be honest; I don't know if I'm going to. But if anybody happens to know what that funkiness is or why fixtures and factories are different in that regard, I would be very intrigued because, at some point, I might look into it just because I would like to know. CHRIS: Oh, that is interesting. I have not really worked with fixtures much at all. I've lived a factory life myself, and thus that's where almost all of my experience is. I'm not super surprised if this ends up being the case, like, the idea that fixtures are just some data that gets shoveled into the database directly as opposed to FactoryBot going through the model layer. And so it's sort of like that difference. But I don't know that for certain. That sounds like what this is and makes sense conceptually. But I think this is what you were saying like, that also kind of pushes me more in the direction of factories because it's like, oh, they're now representative. They're using our model layer, where we're defining certain truths. And I don't love callbacks as a mechanism. But if your app has them, then getting data that is representative is useful in tests. Like one of the things I add whenever I'm working with FactoryBot is the FactoryBot lint rake task RSpec thing that basically just says, "Are your factories valid?" which I think is a great baseline to have. Because you may add a migration that adds a default constraint or something like that to the database that suddenly all your factories are invalid, and it's breaking tests, but you don't know it. Like subtly, you change it, and it doesn't actually break a test, but then it's harder later. So that idea of just having more correctness baked in is always nice, especially when it can be automated like that, so definitely a fan of that. But yeah, interested if you do figure out the distinction. I do like your take, though, of like, but also, maybe I just won't figure this out. Maybe this isn't worth figuring it out. Although you were in the interesting spot of, you could just port the fixtures over and then be done and call the larger body of work done. But it's done in sort of a half-complete way, so it's an interesting trade-off space. I'm also interested to hear where you end up on that. STEPH: Yeah, it's a tough trade-off. It's one that we don't feel great about. But then it's also recognizing what's the true value of what we're trying to deliver? And it also comes down to the idea of churn versus complexity. And I feel like we are porting over existing complexity and even adding a smidge, not actual complexity but adding a smidge of indirection in terms that when someone sees this file, they're going to see a mixed-use of fixtures and factories, and that doesn't feel good. And so we've already talked about adding a giant comment above fixtures that just is very honest and says, "Hey, these were ported over. Please don't mimic this. But this is some legacy tests that we have brought over. And we haven't migrated the fixtures over to use factories." And then, in regards to the churn versus complexity, this code isn't likely to get touched like these tests. We really just need them to keep running and keep validating scenarios. But it's not likely that someone's going to come in here and really need to manage these anytime soon. At least, this is what I'm telling myself to make me feel better about it. So there's also that idea of yes, we are porting this over. This is also how they already exist. So if someone did need to manage these tests, then going to Test::Unit, they would have the same experience that they're going to have in RSpec. So that's really the crux of it is that we're not improving that experience. We're just moving it over and then trying to communicate that; yes, we have muddied the waters a little bit by introducing this other pattern. So we're going to find a way to communicate why we've introduced this other pattern, but that way, we can stay focused on actually porting things over to RSpec. As for the factories versus fixtures, I feel like you're onto something in terms of it's just skipping that model layer. And that's why a lot of that functionality isn't getting run. And I do appreciate the accuracy of factories. I'd much rather know is my data representative of real data that can get created in the world? And right now, it feels like some of the fixtures aren't. Like, how they're getting created seemed to bypass really important checks and validations, and that is wrong. That's not what we want to have in our test is, where we're creating data that then the rest of the application can't truly create. But that's another problem for another day. So that's an update on a trade-off that we have made in regards to the testing journey that we are on. What's going on in your world? CHRIS: Well, we got to do something exciting this week. I was working on some code. This is using dry-monads, the dry-rb space. So we have these result objects that we use pretty pervasively throughout the app, and often, we're in a controller. We run one of these command objects. So it's create user, and create user actually encompasses a ton of logic in our app, and that object returns a result. So it's either a success or a failure. And if it's a success, it'll be a success with that new user wrapped up inside of it, or if it's a failure, it's a specific error message. Actually, different structured error messages in different ways, some that would be pushed to the form, some that would be a flash message. There are actually fun, different things that we do there. But in the controller, when we interact with those result objects, typically what we'll do is we'll say result equals create user dot run, (result=createuser.run) and then pass it whatever data it needs. And then on the next line, we'll say results dot either, (results.either), which is a method on these result objects. It's on both the success and failure so you can treat them the same. And then you pass what ends up being a lambda or a stabby proc, or I forget what they are. But one of those sort of inline function type things in Ruby that always feel kind of weird. But you pass one of those, and you actually pass two of them, one for the success case and one for the failure case. And so in the success case, we redirect back with a notice of congratulations, your user was created. Or, in the failure case, we potentially do a flash message of an alert, or we send the errors down, or whatever it ends up being. But it allows us to handle both of those cases. But it's always been syntactically terrible, is how I would describe it. It's, yeah, I'm just going to leave it at that. We are now living in a wonderful, new world. This has been something that I've wanted to try for a while. But I finally realized we're actually on Ruby 2.7, and so thus, we have access to pattern matching in Ruby. So I get to take it for a spin for the first time, realizing that we were already on the correct version. And in particular, dry-monads has a page in their docs specific to how we can take advantage of pattern matching with the result objects that they provide us. There's nothing specific in the library as far as I understand it. This is just them showing a bunch of examples of how one might want to do it if they're working with these result objects. But it's really great because it gives the ability to interact with, you know, success is typically going to be a singular case. There's one success branch to this whole logic, but there are like seven different ways it can fail. And that's the whole idea as to why we use these command objects and the whole Railway Oriented Programming and that whole thing which I have...what is this word? [laughs] I feel like I should know it. It's a positive rant. I have raved; that is how our users kindly pointed that out to us. I have raved about the Railway Oriented Programming that allows us to do. But it's that idea that they're actually, you know, there's one happy path, and there are seven distinct failure modes, seven unhappy paths. And now, using pattern matching, we actually get a really expressive, readable, useful way to destructure each of those distinct failures to work with the particular bits of data that we need. So it was a very happy day, and I got to explore it. This is, again, a feature of Ruby, not a feature of dry-monads. But dry-monads just happens to embrace it and work really well with it. So that was awesome. STEPH: That is awesome. I've seen one or two; I don't know, I've seen a couple of tweets where people are like, yeah, Ruby pattern matching. I haven't found a way to use it. So I'm excited that you just shared a way that you found to use it. I'm also worried what it says about our developer culture that we know the word rant so well, but rave, we always have to reach back into our memory to be like, what's that positive word or something that we like? [laughs] CHRIS: And especially here on The Bike Shed, where we try to gravitate towards the positive. But yeah, it's an interesting point that you make. STEPH: We're a bunch of ranters. It's what we do, pranting ranters. I don't know why we're pranting. [laughs] CHRIS: Because it's that exciting. That's what it is. Actually, there was an interesting thing as we were playing around with the pattern matching code, just poking around in the console session with it, and it prints out a deprecation warning. It's like, warning: this is an experimental feature. Do not use it, be careful. But in the back of my head, I was like, I actually know how this whole thing plays out, Ruby 2.7, and I assure you, it's going to be fine. I have been to the future, at least I'm pretty sure. I think the version that is in Ruby 2.7 did end up getting adopted basically as it stands. And so, I think there is also a setting to turn off that deprecation warning. I haven't done it yet, but I mostly just enjoyed the conversation that I had with this deprecation message of like, listen, I've been to the future, and it's great. Well, it's complicated, but specific to this pattern matching [laughs] in Ruby 3+ versions, it went awesome. And I'm really excited about that future that we now live in. STEPH: I wish we had that for so many more things in our life [laughs] of like, here's a warning, and it's like, no, no, I've seen the future. It's all right. Or you're totally right; I should avoid and back out of this now. CHRIS: If only we could know how the things would play out, you know. But yeah, so pattern matching, very cool. I'll include a link in the show notes to the particular page in the dry-monads docs. But there are also other cool things on the internet. In an unrelated but also cool thing that I found this week, we use Tuple a lot within our organization for pair programming. For anyone who's not familiar with it, it's a really wonderful piece of technology that allows you to pair program pretty seamlessly, better video quality, all of those nice things that we want. But I found there was just the tiniest bit of friction in starting a Tuple call. I know I want to pair with this person. And I have to go up and click on the little menu bar, and then I have to find their name, then I have to click a button. That's just too much. That's not how...I want to live my life at the keyboard. I have a thing called Bartender, which is a little menu bar manager utility app that will collapse down and hide the icons. But it's also got a nice, little hotkey accessible pop-up window that allows me to filter down and open one of the menu bar pop-out menus. But unfortunately, when that happens, the Tuple window isn't interactive at that point. I can't use the arrow keys to go up and down. And so I was like, oh, man, I wonder if there's like an Alfred workflow for this. And it turns out indeed there is actually managed by the kind folks at Tuple themselves. So I was able to find that, install it; it's great. I have it now. I can use that. So that was a nice little upgrade to my workflow. I can just type like TC space and then start typing out the person's name, and then hit enter, and it will start a call immediately. And it doesn't actually make me more productive, but it makes me happier. And some days, that's what matters. STEPH: That's always so impressive to me when that happens where you're like, oh, I need a thing. And then you went through the saga that you just went through. And then the people who manage the application have already gotten there ahead of you, and they're like, don't worry, we've created this for you. That's one of those just beautiful moments of like, wow, y'all have really thought this through on a bunch of different levels and got there before me. CHRIS: It's somewhat unsurprising in this case because it's a very developer-centric organization, and Ben's background being a thoughtbot developer and Alfred user, I'm almost certain. Although I've seen folks talking about Raycast, which is the new hotness on the quick launcher world. I started eons ago in Quicksilver, and then I moved to Alfred, I don't know, ten years ago. I don't know what time it is anymore. But I've been in Alfred land for a while, but Raycast seems very cool. Just as an aside, I have not allowed myself... [laughs] this is another one of those like; I do not have permission to go explore this new tool yet because I don't think it will actually make me more productive, although it could make me happier. So... STEPH: I haven't heard of that one, Raycast. I'm literally adding it to the show notes right now as a way so you can find The Duke later, and I can find Raycast later [chuckles] and take a look at it and check it out. Although I really haven't embraced the whole Alfred workflow. I've seen people really enjoy it and just rave about it and how wonderful it is. But I haven't really leaned into that part of the world; I don't know why. I haven't set any hard and fast rules for myself where I can't play around with these technologies, but I haven't taken the time to do it either. CHRIS: You've also not found yourself writing thousands of lines of Vimscript because you thought that was a good idea. So you don't need as many guardrails it would seem. That's my guess. STEPH: This is true. CHRIS: Whereas I need to be intentional [laughs] with how I structure my interaction with my dev tools. STEPH: Instead, I'm just porting over fixtures from one place to another. [laughs] That's the weird space that I'm living in instead. [laughs] CHRIS: But you're getting paid for that. No one paid me for the Vimscript I wrote. [laughter] STEPH: That's fair. Speaking around process-y things, there's something that's been on my mind that Valeria, another thoughtboter, suggested around how we structure our meetings and the default timing that we have for meetings. So Thursdays are my team-focused day. And it's the day where I have a lot of one on ones. And I realized that I've scheduled them back to back, which is problematic because then I have zero break in between them, which I'm less concerned about that because then I can go for an hour or something and not have a break. And I'm not worried about that part. But it does mean that if one of those discussions happens to go over just even for like two or three minutes, then it means that someone else is waiting for me in those two to three minutes. And that feels unacceptable to me. So Valeria brought up a really good idea where I think it's only with the Google Meet paid version. I could be wrong there. But I think with the paid version of it that then you can set the new default for how long a meeting is going to last. So instead of having it default to 30 minutes, have it default to 25 minutes. So then, that way, you do have that five-minute buffer. So if you do go over just like two or three minutes with someone, you've still got like two minutes to then hop to the next call, and nobody's waiting for you. Or if you want those five minutes to then grab some water or something like that. So we haven't implemented it just yet because then there's discussion around is this a new practice that we want everybody to move to? Because I mean, if just one person does it, it doesn't work. You really need everybody to buy into the concept of we're now defaulting to 25 versus 30-minute meetings. So I'll have to let you know how that goes. But I'm intrigued to try it out because I think that would be very helpful for me. Although there's a part of me that then feels bad because it's like, well, if I have 30 minutes to chat with somebody, but now I'm reducing it to 25 minutes each time, I didn't love that I'm taking time away from our discussion. But that still feels like a better outcome than making somebody wait for three to five minutes if something else goes over. So have you ever run into something like that? How do you manage back-to-back meetings? Do you intentionally schedule a break in between or? CHRIS: I do try to give myself some buffer time. I stack meetings but not so much so that they're just back to back. So I'll stack them like Wednesdays are a meeting-heavy day for me. That's intentional just to be like, all right, I know that my day is going to get chopped up. So let's just really lean into that, chop the heck out of Wednesday afternoons, and then the rest of the week can hopefully have slightly longer deep work-type sessions. And, yeah, in general, I try and have like a little gap in between them. But often what I'll do for that is I'll stagger the start of the next meeting to be rather than on the hour or the half-hour, I start it on the 15th minute. And so then it's sort of I now have these little 15-minute gaps in my workflow, which is enough time to do one or two small things or to go get a drink or whatever it is or if things do run over. Like, again, I feel what you're saying of like, I don't necessarily want to constrain a meeting. Or I also don't necessarily want to go into the habit of often over-running. I think it's good to be intentional. Start meetings on time, end meetings on time. If there's a great conversation that's happening, maybe there's another follow-up meeting that should happen or something like that. But for as nonsensical of a human as I believe myself to be, I am rather rigid about meetings. I try very hard to be on time. I try very hard to wrap them up on time to make sure I go to the next one. And so with that, the 15-minute staggering is what I've found works for me. STEPH: Yeah, that makes sense. One-on-ones feels special to me because I wholeheartedly agree with being very diligent about like, hey, this is our meeting time. Let's do a time check. Someone says that at the end, and then that way, everybody can move on. But one on ones are, there's more open discussion space, and I hate cutting people off, especially because it might not be until the last 15 minutes that you really got into the meat of the conversation. Or you really got somewhere that's a little bit more personal or things that you want to talk about. So if someone's like, "Yeah, let me tell you about my life goals," and you're like, "Oh, no, wait, sorry. We're out of time." That feels terrible and tragic to do. So I struggle with that part of it. CHRIS: I will say actually, on that note, I'm now thinking through, but I believe this to be true. Everyone that reports to me I have a 45-minute one-on-one with, and then my CEO I set up the one-on-one. So I also made that one a 45-minute one-on-one. And that has worked out really well. Typically, I try and structure it and reiterate this from time to time of, like, hey, this is your space, not mine. So let's have whatever conversation fits in here. And it's fine if we don't need to use the whole time, but I want to make sure that we have it and that we protect it. Because I often find much like retro, I don't know; I think everything's fine. And then suddenly the conversation starts, and you're like, you know what? Actually, I'm really concerned now that you mentioned it. And you need that sort of empty space that then the reality sort of pop up into. And so with one on one, I try and make sure that there is that space, but I'm fine with being like, we can cut this short. We can move on from one-on-one topics to more of status updates; let's talk about the work. But I want to make sure that we lead with is there anything deeper, any concerns, anything you want to talk through? And sort of having the space and time for that. STEPH: I like that. And I also think it speaks more directly to the problem I'm having because I'm saying that we keep running over a couple of minutes, and so someone else is waiting. So rather than shorten it, which is where I'm already feeling some pain...although I still think that's a good idea to have a default of 25-minute meetings so then that way, there is a break versus the full 30. So if people want to have back-to-back meetings, they still have a little bit of time in between. But for one on ones specifically, upping it to 45 minutes feels nice because then you've got that 15-minute buffer likely. I mean, maybe you schedule a meeting, but, I don't know, that's funky. But likely, you've got a 15-minute buffer until your next one. And then that's also an area that I feel comfortable in sharing with folks and saying, "Hey, I've booked this whole 45 minutes. But if we don't need the whole time, that's fine." I'm comfortable saying, "Hey, we can end early, and you can get more of your time back to focus on some other areas." It's more the cutting someone off when they're talking because I have to hop to the next thing. I absolutely hate that feeling. So thanks, I think I'll give that a go. I think I'll try actually bumping it up to 45 minutes, presuming that other people like that strategy too, since they're opting in [laughs] to the 45 minutes structure. But that sounds like a nice solution. CHRIS: Well yeah, happy to share it. Actually, one interesting thing that I'm realizing, having been a manager at thoughtbot and then now being a manager within Sagewell, the nature of the interactions are very different. With thoughtbot, I was often on other projects. I was not working with my team day to day in any real capacity. So it was once every two weeks, I would have this moment to reconnect with them. And there was some amount of just catching up. Ideally, not like status update, low-level sort of thing, but sort of just like hey, what have you been working on? What have you been struggling with? What have you been enjoying? There was more like I needed bigger space, I would say for that, or it's not surprising to me that you're bumping into 30 minutes not being quite long enough. Whereas regularly, in the one on ones that I have now, we end up cutting them short or shifting out of true one-on-one mode into more general conversation and chatting about Raycast or other tools or whatever it is because we are working together daily. And we're pairing very regularly, and we're all on the same project and all sorts of in sync and know what's going on. And we're having retro together. We have plenty of places to have the conversation. So the one-on-one again, still, I keep the same cadence and the same time structure just because I want to make sure we have the space for any day that we really need that. But in general, we don't. Whereas when I was at thoughtbot, it was all the more necessary. And I think for folks listening; I could imagine if you're in a team lead position and if you're working very closely with folks, then you may be on the one side of things versus if you're a little bit more at a distance from the work that they're doing day to day. That's probably an interesting question to ask, and think about how you want to structure it. STEPH: Yeah, I think that's an excellent point. Because you're right; I don't see these individuals. We may not have really gotten to interact, except for our daily syncs outside of that. So then yeah, there's always like a good first 10 minutes of where we're just chatting about life and catching up on how things are going before then we dive into some other things. So I think that's a really good point. Cool, solving management problems on the mic. I dig it. In slightly different news, I've joined a book club, which I'm excited about. This book club is about Ruby. It's specifically reading the book Ruby Science, which is a book that was written and published by thoughtbot. And it requires zero homework, which is my favorite type of book club. Because I have found I always want to be part of book clubs. I'm always interested in them, but then I'm not great at budgeting the time to make sure I read everything I'm supposed to read. And so then it comes time for folks to get together. And I'm like, well, I didn't do my homework, so I can't join it. But for this one, it's being led by Joël, and the goal is that you don't have to do the homework. And they're just really short sections. So whoever's in charge of leading that particular session of the book club they're going to provide an overview of what's covered in whatever the reading material that we're supposed to read, whatever topic we're covering that day. They're going to provide an overview of it, an example of it, so then we can all talk about it together. So if you read it, that's wonderful. You're a bit ahead and could even join the meeting like five minutes late. Or, if you haven't read it, then you could join and then get that update. So I'm very excited about it. And this was one of those books that I'd forgotten that thoughtbot had written, and it's one that I've never read. And it's public for anybody that's interested in it. So to cover a little bit of details about it, so it talks about code smells, ways to refactor code, and then also common patterns that you can use to solve some issues. So there's a lot of really just great content that's in it. And I'll be sure to include a link in the show notes for anyone else that's interested. CHRIS: And again, to reiterate, this book is free at this point. Previously, in the past, it was available for purchase. But at one point a number of years ago, thoughtbot set all of the books free. And so now that along with a handful of other books like...what's Edward's DNS book? Domain Name Sanity, I believe, is Edward's book name that Edward Loveall wrote when he was not a thoughtboter, [laughs] and then later joined as a thoughtboter, and then we made the book free. But on the specific topic of Ruby Science, that is a book that I will never forget. And the reason I will never forget it is that book was written by the one and only CTO Joe Ferris, who is an incredibly talented developer. And when I was interviewing with thoughtbot, I got down to the final day, which is a pairing session. You do a morning pairing session with one thoughtbot developer, and you do an afternoon pairing session with another thoughtbot developer. So in the morning, I was working with someone on actually a patch to Rails which was pretty cool. I'd never really done that, so that was exciting. And that went fine with the exception that I kept turning on Caps Lock on their keyboard because I was used to Caps Lock being CTRL, and then Vim was going real weird for me. But otherwise, that went really well. But then, in the afternoon, I was paired with the one and only CTO Joe Ferris, who was writing the book Ruby Science at that time. And the nature of the book is like, here's a code sample, and then here's that code sample improved, just a lot of sort of side-by-side comparisons of code. And I forget the exact way that this went, but I just remember being terrified because Joe would put some code up on the screen and be like, "What do you think?" And I was like, oh, is this the good code or the bad code? I feel like I should know. I do not know. I'm not sure. It worked out fine, I guess. I made it through. But I just remember being so terrified at that point. I was just like, oh no, this is how it ends for me. It's been a good run. STEPH: [laughs] CHRIS: I made it this far. I would have loved to work for this nice thoughtbot company, but here we are. But yeah, I made it through. [laughs] STEPH: There are so many layers to that too where it's like, well if I say it's terrible, are you going to be offended? Like, how's this going to go for me if I speak my truths? Or what am I going to miss? Yeah, that seems very interesting (I kind of like it.) but also a terrifying pairing session. CHRIS: I think it went well because I think the code...I'd been following thoughtbot's work, and I knew who Joe was and had heard him on podcasts and things. And I kind of knew roughly where things were, and I was like, that code looks messy. And so I think I mostly got it right, but just the openness of the question of like, what do you think? I was like, oh God. [laughs] So yeah, that book will always be in my memories, is how I would describe it. STEPH: Well, I'm glad it worked out so we could be here today recording a podcast together. [laughs] CHRIS: Recording a podcast together. Now that I say all that, though, it's been a long time since I've read the book. So maybe I'll take a revisit. And definitely interested to hear more about your book club and how that goes. But shifting ever so slightly (I don't have a lot to say on this topic.) but there's a new framework technology thing out there that has caught my attention. And this hasn't happened for a while, so it's kind of novel for me. So I tend to try and keep my eye on where is the sort of trend of web development going? And I found Inertia a while ago, and I've been very, very happy with that as sort of this is the default answer as to how I build websites. To be clear, Inertia is still the answer as to how I build websites. I love Inertia. I love what it represents. But I'm seeing some stuff that's really interesting that is different. Specifically, Remix.run is the thing that I'm seeing. I mentioned it, I think, in the last episode talking about there was some stuff that they were doing with data loading and async versus synchronous, and do you wait on it or? They had built some really nice levers and trade-offs into the framework. And there's a really great talk that Ryan Florence, one of the creators of Remix.run, gave about that and showed what they were building. I've been exploring it a little bit more in-depth now. And there is some really, really interesting stuff in Remix. In particular, it's a meta-framework, I think, is the nonsense phrase that we use to describe it. But it's built on top of React. That won't be true for forever. I think it's actually they would say it's more built on top of React Router. But it is very similar to Next.js for folks that have seen that. But it's got a little bit more thought around data loading. How do we change data? How do we revalidate data after? There's a ton of stuff that, having worked in many React client-side API-heavy apps that there's so much pain, cache invalidation. How do you think about the cache? When do you fetch from the network? How do you avoid showing 19 different loading spinners on the page? And Remix as a framework has some really, I think, robust and well-thought-out answers to a lot of that. So I am super-duper intrigued by what they're doing over there. There's a particular video that I think shows off what Remix represents really well. It's Ryan Florence, that same individual, the creator of Remix, building just a newsletter signup page. But he goes through like, let's start from the bare bones, simplest thing. It's just an input, and a form submits to the server. That's it. And so we're starting from web 2.0, long, long ago, sort of ideas, and then he gradually enhances it with animations and transitions and error states. And even at the end, goes through an accessibility audit using the screen reader to say, "Look, Remix helps you get really close because you're just using web fundamentals." But then goes a couple of steps further and actually makes it work really, really well for a screen reader. And, yeah, overall, I'm just super impressed by the project, really, really intrigued by the work that they're doing. And frankly, I see a couple of different projects that are sort of in this space. So yeah, again, very early but excited. STEPH: On their website...I'm checking it out as you're walking me through it, and on their website, they have "Say goodbye to Spinnageddon." And that's very cute. [laughs] CHRIS: There's some fundamental stuff that I think we've just kind of as a web community, we made some trade-offs that I personally really don't like. And that idea of just spinners everywhere just sending down a ball of application logic and a giant JavaScript file turning it on on someone's computer. And then immediately, it has to fetch back to the server. There are just trade-offs there that are not great. I love that Remix is sort of flipping that around. I will say, just to sort of couch the excitement that I'm expressing right now, that Remix exists in a certain place. It helps with building complex UIs. But it doesn't have anything in the data layer. So you have to bring your own data layer and figure out what that means. We have ActiveRecord within Rails, and it's deeply integrated. And so you would need to bring a Prisma or some other database connection or whatever it is. And it also doesn't have more sort of full-featured framework things. Like with Rails, it's very easy to get started with a background job system. Remix has no answer to that because they're like, no, no, this is what we're doing over here. But similarly, security is probably the one that concerns me the most. There's an open conversation in their discussion portal about CSRF protection and a back and forth of whether or not Remix should have that out of the box or not. And there are trade-offs because there are different adapters that you can use for auth. And each would require their own CSRF mitigation. But to me, that is the sort of thing that I would want a framework to have. Or I'd be interested in a framework that continues to build on top of Remix that adds in background jobs and databases and all that kind of stuff as a complete solution, something more akin to a Rails or a Laravel where it's like, here we go. This is everything. But again, having some of these more advanced concepts and patterns to build really, really delightful UIs without having to change out the fundamental way that you're building things. STEPH: Interesting. Yeah, I think you've answered a couple of questions that I had about it. I am curious as to how it fits into your current tech stack. So you've mentioned that you're excited and that it's helpful. But given that you already have Rails, and Inertia, and Svelte, does it plug and play with the other libraries or the other frameworks that you have? Are you going to have to replace something to then take advantage of Remix? What does that roadmap look like? CHRIS: Oh yeah, I don't expect to be using Remix anytime soon. I'm just keeping an eye on it. I think it would be a pretty fundamental shift because it ends up being the server layer. So it would replace Rails. It would replace the Inertia within the stack that I'm using. This is why as I started, I was like, Inertia is still my answer. Because Inertia integrates really well with Rails and allows me to do the sort of it's not progressive enhancement, but it's like, I want fancy UI, and I don't want to give up on Rails. And so, Inertia is a great answer for that. Remix does not quite fit in the same way. Remix will own all of the request-response lifecycle. And so, if I were to use it, I would need to build out the rest of that myself. So I would need to figure out the data layer. I would need to figure out other things. I wouldn't be using Rails. I'm sure there's a way to shoehorn the technologies together, but I think it sort of architecturally would be misaligned. And so my sense is that folks out there are building...they're sort of piecing together parts of the stack to fill out the rest. And Remix is a really fantastic controller and view from their down experience and routing layer. So it's routing, controller, view I would say Remix has a really great answer to, but it doesn't have as much of the other stuff. Whereas in my case, Inertia and Rails come together and give me a great answer to the whole story. STEPH: Got it. Okay, that's super helpful. CHRIS: But yeah, again, I'm in very much the exploratory phase. I'm super intrigued by a lot of what I've seen of it and also just sort of the mindset, the ethos of the project as it were. That sounds fancy as I say it, but it's what I mean. I think they want to build from web fundamentals and then enhance the experience on top of that, and I think that's a really great way to go. It means that links will work. It means that routing and URLs will work by default. It means that you won't have loading spinner Armageddon, and these are core fundamentals that I believe make for good websites and web applications. So super interested to see where they go with it. But again, for me, I'm still very much in the Rails Inertia camp. Certainly, I mean, I've built Sagewell on top of it, so I'm going to be hanging out with it for a while, but also, it would still be my answer if I were starting something new right now. I'm just really intrigued by there's a new example out there in the world, this Remix thing that's pushing the envelope in a way that I think is really great. But with that, my now…what was that? My second or my third rave? Also called the positive rant, as we call it. But yeah, I think on that note, what do you think? Should we wrap up? STEPH: Let's wrap up. CHRIS: The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!!!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

The Bike Shed
343: Opt-In To Oversharing

The Bike Shed

Play Episode Listen Later Jun 21, 2022 30:31


Chris is weathering through a slight lull, a holding period, where his team waits for new features to become available with some of the platforms they integrate with, and as they think out new facets of the platform they're building. Steph has been thinking recently about working in isolation. It's a topic that Joël Quenneville pointed out to her and mentioned. Can engineers work in isolation and be successful? Become a Sponsor (https://thoughtbot.com/sponsorship) of The Bike Shed! Transcript: CHRIS: Always be singing. STEPH: I can't remember if I've shared the story with you. But I had a beautiful little human moment with someone at airport security. Because when I travel with my mic, I always get stopped because there's the middle long, thin piece that looks like what you would screw on to a gun like for a silencer. And so [laughs] as he was going through, the person was looking at it, and then he called over a buddy. And then they called over another buddy, and there's like three TSA agents all looking at the X-ray screen. And finally, they're like, "Yeah, we need to flag it." So they moved it over. And then he was digging through, and he pulled out the big metal piece. And I said, "It's for a microphone." And he's like, "Okay," and he kept looking, and then he finally found the microphone. And he lit up because I guess he wasn't really sure to believe me at first when I said it. But he lit up, and he was like, "Karaoke?" [laughs] I was like, "No, it's for podcasting." CHRIS: But not 100% no because we do sing plenty on this show, so... STEPH: I think that's what made me think of it. It was your singing. [laughs] CHRIS: Yep. My wonderful, wonderful singing. STEPH: Hello and welcome to another episode of The Bike Shed, a weekly Podcast from your friends at thoughtbot about developing great software. I'm Steph Viccari. CHRIS: And I'm Chris Toomey. STEPH: And together, we're here to share a bit of what we've learned along the way. So, hey, Chris? What's new in your world? CHRIS: What's new in my world? We are in sort of a...what's the word? There's a bit of a lull right now, not like a big lull, but we had a bunch of clear work that came into the team, did a bunch of iterations, some testing, built some new features, et cetera. And now there's a small holding period basically where we wait for some new features to become available with some of the platforms that we integrate with and also as we think out some new facets of the platform that we're building. So we've got this little bit of time here where we're not necessarily building out as many new novel features. But instead, as a dev team, we're taking this moment to be like, oh, cool, let's tie down. I want to make a sailing analogy here, but I don't know sailing. It's like tie down the somethings and batten the hatches, maybe. That sounds like a thing. [chuckles] But so we have a couple of projects going right now. We want to really accept the truth and lean into Sidekiq. So right now, we have a mix of ActiveJob and Sidekiq jobs. And they're confusing, and et cetera, et cetera. So we want to kind of lean into that, upgrade dependencies, that sort of thing. We are, again, doing a little bit of work on the observability foundation of our system. so how do we know what's going on at runtime? Also, working on just some core features and functionality. We have done a little bit of an exploration into the event processing stuff, some of that that I've been talking about. It's actually been very interesting. So we're working with Customer.io as a platform, which is omnichannel communication behavior-based messaging sort of thing. So when a user does X, send them an email and then wait three days. And if they haven't responded, then do this other thing. And I think I've said this in previous episodes; I'm so wildly impressed with that platform. They have done such a good job. And I know that good software doesn't happen in a vacuum. In fact, if we're being honest, a lot of the software out there is not very good. And not only do they do a good job, but it's across...there's a ton of functionality in Customer.io. And it's interesting because we're finding ourselves leaning into it even more because it is such a solid platform and because it connects into our event system. Like, it's a segment destination, so all of our analytics events get piped into Customer.io, and then we can action on any of them. And the actions can be quite complicated. And this is where we're getting into good idea, terrible idea space. And to be clear, this is still just an exploration. But we basically wanted a way to do more. There are a bunch of different actions that you can take so, like send an email, send an SMS, or there are a couple of other slightly fancier ones. You can trigger an event within the Customer.io system. You can actually do an arbitrary HTTP POST, PUT, PATCH, whatever, any web requests you want to make. So if you want to integrate with essentially anything else out there, you can do that. You can send some structured data over the wire. And so we've now been like, okay, what if, and stay with me here, what if we use our analytic system and we send events whenever a user does something, and then that event eventually trickles down to Customer.io? Within that, we allow ourselves to respond to that event by emitting a different event within the system, within Customer.io. And then, via the webhook functionality, we fire that back to the Rails application. And then there we can do whatever we want. And in a way, that sounds absurd because we're starting from our app, and then we're sending some events down, processing them in certain ways, sending it back to the app, and then maybe doing something. In particular, one of the things we want to do is richly formatted Slack alerts. And Customer.io has a Slack alert functionality, but they can't have any of the fancy stuff. They can't link to our customer in the admin dashboard. So we found that that functionality is particularly useful for our admin team. And so we're like, ah, this feels weird. But if we were to do this loop out and back, then ideally, we get the power of Customer.io for non-technical users or non-engineering team users to configure workflows and to say, "When a user does this, I actually want to alert the admin team via Slack." And we want it to be rich and have buttons that you can click and all that kind of stuff. And although the thing that I just described seems complicated, is a word that I'll use for it, confusing at times, it isn't...like, I don't want to do all of that in the app. I don't want the app to have to think about how do I wait three days? We technically can do that with Sidekiq, but it gets us in trouble and whatnot, whereas Customer.io that's a core concept for them. And so, again, very much exploration. This will probably be a future good idea, terrible idea segment. But that's been an interesting one to explore. STEPH: You have quite a talent for you preface something as a bad idea, and you do a very good job of making it sound reasonable and good. [laughs] So it's interesting to be on that side of like, good idea, bad idea. It's like, I'm looking for the bad. And I have questions, but overall, [chuckles] you do a very good job of being very thoughtful and walking through why it makes sense or what are the benefits of it. So you answered some of my questions around why still send it to Customer.io versus just having it all in-house. So the fact that the admin team has access to it makes a lot of sense. I want to clarify one point. So when you send it to Customer.io, Customer.io then needs to send a message back to your application. And then that's when you customize the Slack message. Do you need Customer.io to send that message, or could you just fire off an event to Customer.io to say, "Hey, capture this, but don't do anything with this. And then we're going to send the Slack message because we want to customize it."? CHRIS: I think the key is that we want to leverage the fact that Customer.io is the platform that our operations team really is now becoming comfortable with and using for this behavioral automation workflow type logic. So that idea of when this event, you know, when this triggering event happens, if this condition is true, then respond in this way. And so because Customer.io is the platform that A, is quite good at that and B, is where our admin team is now thinking about doing that, one thing that we might do let's say a user completes some action within the application. So they fill out a form to submit their interest in some new platform feature. Initially, what we might want to do there is alert ourselves to say, "Hey, this happened. Take some action." And then eventually, we may want to instead switch that over and send an email to the customer with the next steps that they need to do. And the ability to gradually transition across that spectrum is really interesting to me, and again, Customer.io being the platform, sort of the hub for how we respond to these events. At the same time, I know that this feels like a generic message processing system that might be a Kafka queue somewhere else. And so I've got that in the back of my head of like, is this weird? I think it's a little weird. But it also, thus far as we're exploring it, is very approachable for the admin team, very familiar for them, and reasonably powerful. And also, there's a drag and drop editor for the events and the payloads. And it knows for this event, here's the stuff that's available to you. And so the ability for our admin team to interact with that interface is really great. And we don't have to build it. We don't have to think about it. But I will say I've worked at so many different companies that have their ad hoc system that makes it easy to do generic X, Y, and Z. And it's bad, and it falls down. And it's impossible to know when anything happens. And so, I've got a lot of concerns in the back of my head, which I will want to at least think through and understand the trade-offs that we're making if we pursue this path, but it is very interesting to me. So right now, a lot of this logic does live in the app. But it means that it requires a code change for anything that we want to do like this. We want to have a Slack alert whenever X happens. Now, the developers are in the loop for all of that. And really, it's the operations team that owns the decisioning on that. And so if they can also self-serve and instrument the action, the alert, the follow-up, the whatever it is, if we can give them those primitives in a platform that they already understand, that sounds nice. I'm intrigued, is what I'll say. So anyway, while we're in this lull period, we are trying out some fun stuff like that and exploring those sorts of things. STEPH: I like that perspective that you're putting on it, or at least the one that's standing out to me is the concept of ownership is like who gets to own these actions. But then beyond that, that's the part where I feel a little squirmy is, so we are using this third-party tool because it makes life easier. But then, at what point when we start building software around this third-party tool to then customize it back on our own side. Then if someone is in Customer.io, so if an admin user is in there and then they trigger an event, is there going to be confusion as to what's going to happen? And can they retry an event? Because I'm realizing my initial suggestion where it was like, hey, notify Customer.io that this is there but then also manage sending the Slack message that would prevent them from being able to have that retry capability. And that may be very much worth preserving. So then it's understood that hey, if you want to manage this, we are giving you full access to manage this work. We may customize it, but this is still the interface in which you go through to have three tries or to manage that workflow or these actions that get sent to users. CHRIS: Yeah. I think you've perfectly highlighted the why this might not be a great idea or at least the concerns to explore before adopting this more thoroughly. And even just the idea of adopting it more thoroughly, like, how tied into the system are we? How business-critical does this new external piece of software become? Because I've seen that to be really problematic where there are organizations that I've worked with that are like, "Oh God, we would love to move off of system X. But unfortunately, it's basically the one thing holding this business up." And I'm like, yeah, I get that. And that happens. So yeah, being really intentional with that. And that's why we're very much in an exploration place. But we have a bunch of stuff that we've done that required engineering work. And we're now seeing like, actually, could we map this into this other tool? And can we build the set of primitives in that space that now this team can own that whole experience? And then critically, can they debug it? Will we know when something goes wrong, et cetera? Those are always parts. At this point, I don't think I can just imagine a happy path. And I hope this isn't true for the rest of my life. But the work as a software developer, especially after having done a couple of rounds of it and as a consultant, I just imagine failure modes. It's all I do. I'll be like, okay, we just need to wire X up to Z, and then we need to fire off a request. And then, once we get the message back, then we can process them. I'm like, right. You just described 13 things that can go wrong. Now let's imagine each of the different failure states because that's all I'm going to do. Who cares about the happy path? Those are easy. Those write themselves. It's all of the failure modes that I need to think about. And someday, when I retire, and I go to a log cabin in the woods, and I don't talk to people for a while, maybe I'll go back to a place of only happy paths. But that is not my truth right now. STEPH: I can't tell you how many people in my personal life I have annoyed so much [laughs] because all I see are failure modes. And one, that's a delightful t-shirt. [laughs] I'd love to have that. And then yeah, I feel you because there are so many times where someone is...like, I'm with someone who's like a big idea person. And so they're just launching into what-ifs, and we did this. And I can't help it, and I have learned to help it. But it has been a struggle with some strong feedback from family and friends to reel it in. Because then I will start to think through okay, well, what's the details? And I have some questions. What happens when this happens? And yeah, all I see are failure modes. [laughs] It is very true for me too, and not always...not so great. So I, too, shall get a log cabin one day and try to forget all of that. CHRIS: I will say I painted that as a particularly glib version of myself. But some of what I'm doing right now, particularly joining an early-stage startup and taking the role of CTO, was very much to try and intentionally resist that. Because right now, I have to be really careful with how much of the potential edge cases and whatnot. I'm considering exactly how robust of a platform are we building? Very is the answer. But what about extremely? Because extremely is an option but extremely costs four times as much. Mostly in time being the critical element there. And so part of the work that I'm doing now is just trying to push on those edges, push on those boundaries, find the places where we can move quickly, and still build a robust platform because frankly, we're building...Sagewell is a financial platform under the hood, and I can't be flippant with that. We as a team have to be really careful with the thing that we're building. But we also have to move quickly. We have to be able to iterate. We have to be able to build something and try it out and see if it works. And then, if it doesn't, maybe shelve it and pull it out of the codebase. And it has been a real challenge, but it was the challenge that I wanted here. And so I've been enjoying that work, but it has been a stretch, a growth moment, let's call it. STEPH: I don't know if you've shared that particular goal with me in transitioning to a CTO role, but I really, really like it. One, it's very aligned with who you are. You're very thoughtful, and you look for areas to push and ways to do that. And then I also struggle in those areas, and thoughtbot specifically and consulting has helped push me in directions, push me out of my comfort zones but still in a safe space where I have other people to talk to as I'm making those decisions and pushing past the comfort areas that I have. But one of them is that I will initially think things have to be perfect or really planned. And I had a really nice conversation with Chad Pytel, who is one of the Founders of thoughtbot and also COO and host of the Giant Robots Smashing Into Other Giant Robots Podcast. And we were chatting about a new offering that thoughtbot is bringing to the market. And it's one that I've been involved with. And I started getting really in the weeds of like, but we really have to plan out how this is going to look and all the actions that need to take place before then we can really sell this type of engagement to a new client. And as I was going through this list of worries, when I was done, he mentioned he's like, "All of those are valid and something to consider." He's like, "But we don't have any customers yet." So the first part is we feel that we are in a space that we have enough of information to get started. And it's something that we've done before. And then, we'd like to see where customers align with us on this need because we're going to end up shaping this work in response to what their needs are. And so, we can't really begin that shaping until we understand more of what people are looking for. I was like, oh yeah, that's such a nice point. It just reminded me in regard to pushing those boundaries of yes, we need planning upfront, and we look for failure modes. But then there's also an important aspect of then finding ways to keep moving forward and getting more feedback and then balancing those two. CHRIS: Yeah, I think that's definitely right the as always, anchoring it to the customer. What is it that they need? How do we connect with them and hear from them? And ideally, keep those feedback loops as short as possible. That's the game, and everything else fits around that. But yeah, so we're trying some stuff. We'll see how it goes. I will certainly report back, depending on how it plays out. But that's a little bit of what's up in my world. What's up in your world? STEPH: I have been thinking recently about working in isolation. It's a topic that Joël Quenneville, who's another thoughtboter and has been on the show a number of times, it was a topic that he'd actually pointed out to me and mentioned. And so, I wanted to bring that here and share it with you because I'd love to get some of your thoughts on this as well. But I've typically had the viewpoint that when developers are sent off to work on a large, nebulous task, that it's a recipe for disaster, and almost everyone's going to lose in that scenario. And it tends to be a combination of isolation, very distant due dates, and loosely defined scope that leads to those really poor results. However, as developers, it's not inconceivable for us to land in that position. And it's very similar to my current project, who I'm working with Joël on, where we were given a very fuzzy project with some really aggressive goals, and the engagement is going really well. So that led Joël and I to wonder why is this working? This is the thing that we said that people should never do, but it's actually going quite well for us. So reflecting upon some of the things that are working well for us, even though we are in more of an isolated state than we would typically work, some of the things that I've been reflecting on or some of the strategies I should say that we've applied to this situation is number one, we did work hard to plug into an existing team. So when we joined, we joined more of an ad hoc volunteer team. And in everybody's spare time, those individuals were then contributing to the CI process in terms of trying to speed things up and improve things for the rest of the team. But otherwise, there wasn't really a team. There wasn't much structure to it. So it felt like everybody was very much off in their own world doing their own thing, occasionally putting up some code changes for review. And then you had to gain a lot of context to understand what it was that they were doing. So one of the things that I advocated for early on that I thought was more of just my personal preference but I think has actually worked well in regards to the success of the project as well is to plug into an existing team. So even if you are not working with that team on their day-to-day tasks, but you want to have more people to interact with and more people to share your context with. So you are essentially reducing the isolation of you're no longer these two people who are off in a corner working on something, and nobody has any idea what you're doing, and only one person is getting a status update. There is now a whole channel or team of people that have some insight as to what's going on. And they can also really unblock you for when you get stuck because then if you do have a question, but there's that one person who has been like your go-to person for this whole project, if they're out on vacation, or if they leave, or just something happens, you're suddenly blocked. And you don't know who to go to because you've been part of this larger company, but you haven't interacted with anybody outside of that one person. So at least if you're plugged into another team, you've immediately got some friends or some other people to go to and say, "Hey, I'm not sure who can help me with this, but I have this problem." And then, from there, you can get more help. CHRIS: This is super interesting. To start, I really like that you're framing this in terms of this is a thing that we often recommend against or see as an anti-pattern, and yet in this particular case, it's working. Let's look at that. Because I think the things that you're like, huh, that's interesting. That phrase "Huh, that's interesting" is very interesting. It often highlights like oh, something is behaving counter to how we would expect it to, so let's dig in and explore that. And so I love that that was the reaction and then sort of the conversation that spilled out of that. I'm also not super surprised that the combination of you and Joël were able to find a way to make this successful because you are two of the most capable developers that I've worked with but also particularly excellent communicators and advocates for the work that you're doing and the way that one should do the work. So the idea that there's a situation that may not be the ideal mode of working and that you're able to take that and say, "What if we shift it just a little bit and make it a little bit more manageable and whatnot?" So unsurprised, frankly, that you found a way collectively to make this a little bit better. And then I think yeah, it sounds like you're doing the things...so just like, we're in isolation, hmm, that doesn't seem great. Let's unisolate and connect to some people, and that just feels so true. I'm very interested to hear, though. I'm guessing there's more to this story or other things that you've done. Are there other tactics or ways that you've shifted this around? STEPH: Yeah, there's a couple more. So this is one that (And thank you for the kind words.) this was one that I think Joël is really exceptional at. So Joël is really good at building diagrams and graphs and then sharing that with the team as sort of like we've spent a couple of days understanding this big, messy concept. Here's a nice condensed graph that shows how we went about understanding this. And then here's the big overall picture of what we've learned from this, which has been wonderful for so many reasons. And every time that we share something with the team, one, it just helps build camaraderie, especially in remote days, it just builds camaraderie on hey, we're all online. And we're working. And here's the thing that I'm working through or struggling with or something that I learned. I often do that, especially when I get frustrated and something goes wrong. I love to share the I did this today. It went terribly. [laughs] Let me tell you about it, so you're aware of it in case it helps you. And specifically, the diagrams are really nice because then other people can just see and appreciate it, or they can point something out that we didn't know. Or they'll see a different angle because they're more familiar with the system. So they can say, "Oh yeah, that totally makes sense," or "I had no idea that was happening." So that's been a really nice way to engage with the team. And so, essentially, the little title for that strategy is just overshare. Just share all the things that you're doing and find ways to make it digestible for the team so then they can go along on this big, nebulous journey with you. And you can also put it in threads so that way, you're not flooding a channel, but then people can opt-in to that oversharing if they would like more insight into the work that you're doing. CHRIS: Opt-in to that oversharing. [laughs] STEPH: Exactly. I mean, it's not forced oversharing; it's just it's here if people would like it. That was a really nice compliment that some other thoughtboters received from their client team is someone had mentioned that there's so much information that's getting shared from the thoughtboters that they had trouble keeping up. And they really liked that. They really appreciated that they could then go check out this channel or these threads and see exactly the type of work that was happening and the outcomes of it. And then they could just check it maybe beginning of the day, end of the day and get that knowledge dump. Some of the other strategies that we've used are giving ourselves mini-goals to accomplish as part of the larger, more nebulous task. So as we have this very large goal in mind, it's like, where's the small piece? Where's an entry point? What's a task or a goal that we can define? And then we want to break that down into what questions do we need to ask? How can we start moving in this direction? And we want to find something that has an answer. So each time that we start researching once we've gotten to that point...and this is hard. I feel like people may know that, but I should just say that this is hard to take something nebulous and then find the entry point and break down some goals. And that has been one of the wonderful parts of then having a buddy for this type of project because then we can bounce ideas off of each other. And we can also help the other person not go too deep into an area. Because I have definitely had moments where I've been very passionate about like, "We need to do this," and Joël is just like, do we? And I'm like, "Yeah." And he's like, "Do we though?" And I'm like, "I guess not. I just really, really want to." [laughs] It's been very helpful to have a partner balance some of those feelings. And once you can break down some of that amorphous problem into those smaller goals, then you can also create tickets, which is also a really nice way to then surface the work that you're doing. You can document how you're researching, document the question. And then once you have that question of what you're in search of, it's so nice because then once you find the answer, that's immediately a good moment to pause and reflect. So I think in a recent episode, we were chatting about this where Joël and I were trying to understand why the tests weren't being balanced properly across each process that was available. And we found the answer, and we started immediately digging into fixing it or solutions. And then it took us a moment to go back and say, "Actually, this ticket is really just about understanding the problem, not fixing the problem." And so that was a nice; now that we understand the problem, let's go back high-level to define our next goal from this big, nebulous task because maybe fixing that balancing is the right thing to do, but maybe not, and we just need to reconsider. So for that portion of breaking down a big, nebulous task and then identifying smaller tasks that you can achieve, time-boxing has been huge for us in regards of what's something that we can accomplish this week, or what's something we can accomplish today that will then move us forward? And then making sure that we are setting deadlines for ourselves. So normally, this is another area where it's like, huh, that's interesting. I'm a big believer in deadlines. But I do think self-imposed deadlines are really helpful. CHRIS: I'm intrigued to hear you say that you're not a big fan of deadlines because I assume we're actually more aligned on this. But deadlines that are arbitrary and also come with fixed scope and other immovable things, yes, those are the worst in the world. But deadlines that we set for ourselves, and then we use that as a mechanism to hone and refine the scope that we're going to get out the door by that deadline, I find those incredibly useful. And that sounds like that's the same sort of thing you have going on here is like by saying we're willing to expend this much to get a result, that defines the work going into it. STEPH: Yeah, that's fair. Everything that you said is true, too; in regards to, I'm realizing I default that when I hear the word deadline, I'm so used to teams having deadlines that are defined by other individuals that are not part of the work. And as you said, the scope has already been defined, and it can't be changed. And it's all of the bad things that then go with it. So when I think of deadlines, I immediately think of that type of deadline versus the more self-imposed, yes, we can revisit, yes, the team has bought in and understands why this is important. Those types of deadlines are very helpful. It's that first part that I default to that I think of immediately, and I need some reassurance that that is not the type of deadline that I'm looking at or being forced to meet. I have a very similar feeling for estimates. Like, those both fall in the same category for me is; as soon as I hear estimation and deadline, I get nervous. And then I just need to understand the purpose of both and who is setting both of those and the communication around them. And then what does that failure mode look like, the one that we're always looking for? So yeah, deadlines and estimations fit into that. Initially, I'm very hesitant and cautious, but I think they're both very good tools. CHRIS: Yeah, I feel like those are very closely related. And they're definitely tools that can be used for great good or for great evil. And so, ideally, we advocate for the great good usage. But more generally, I love, again, the sharing around the process and what's worked for you in this less typical or often somewhat problematic workflow. I will say, again, so I gave you the series of compliments earlier, and I stand by those compliments for you and Joël. But I think also the sort of related aspect is that you two are both quite senior, very capable, very comfortable suggesting changes, suggesting workflows. So I think the potential dangers of isolation are still very much there. And the fact that the two of you have been able to find a way to work more effectively and perhaps change the terms of things just a little bit to make this effective is A, unsurprising but B, not something that I would expect of every team. I think you've described a wonderful list of the specifics as to how you did that. And ideally, if folks that are perhaps a little earlier on in their career are sent out for a month with a wild project, and they're sent to do it in isolation, hopefully, they can borrow from that list. But again, I do think this is a thing that, from an organizational perspective, we should be very careful with when we're imposing this isolation on it because it takes two fantastic folks like you and Joël to break out of the shackles of it. STEPH: The more we're talking about this, the more apparent it's also becoming that I started with this; how do you manage isolation? And my answer is you get out of it. [laughs] Get out of isolation as quickly as possible. Someone thought it was a good idea to put you there or a good idea to structure it that way. Or maybe they didn't mean it intentionally, but that's how things then shook out. So that's really what a lot of those strategies are about is, then how do I get myself out of this corner that you put me in? Because nobody put Stephanie in a corner. So it's essentially that's all the strategies are looking for ways to say, hey, I'm isolated, but I really don't want to be, and it's dangerous for me to be isolated in this way. Even as a more senior capable developer, it's more likely that things could go wrong, and miscommunications, misaligned expectations. So I need to find ways to then bring the work that I'm doing to make it more relevant to other people on the team. So then we can have more overlap, or at least I can share a lot of the work that's being done. CHRIS: Yeah, absolutely. I think with that wonderful summary and, frankly, utterly fantastic movie reference, what do you think? Should we wrap up? STEPH: Let's do it. Let's wrap up. CHRIS: The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeeeee!!!!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

Closing Bell
Closing Bell Overtime: Navigating the Big Downturn 06/16/22

Closing Bell

Play Episode Listen Later Jun 16, 2022 44:24 Very Popular


Stocks dropped in today's session, with the Nasdaq closing down more than 4%. Wharton School Professor Jeremy Siegel gives instant reaction to the brutal trading day. Plus, Morgan Stanley's Chris Toomey breaks down where he is seeing opportunity in the market. And, Mike Santoli's “Last Word” with his expert take on the big market slide.

The Bike Shed
342: Sky Icing

The Bike Shed

Play Episode Listen Later Jun 14, 2022 43:42


Another toaster strudel debate?! Plus, the results are in for the most listened-to podcast in the RoR community! :: drum roll :: Steph has a "Dear Gerrit" message to share. Chris has a follow-up on mobile app strategy. The Bike Shed: 328: Terrible Simplicity (https://www.bikeshed.fm/328) When To Fetch: Remixing React Router - Ryan Florence (https://www.youtube.com/watch?v=95B8mnhzoCM) Virtual Event - Save Time & Money with Discovery Sprints (https://thoughtbot.com/events/save-time-money-with-discovery) Become a Sponsor (https://thoughtbot.com/sponsorship) of The Bike Shed! Transcript: STEPH: thoughtbot's next virtual event "Save Time & Money with Discovery Sprints" is coming up on June 17th, from 2 - 3 PM Eastern. It's a discussion with team members from product management, design and development. From a developer perspective, topics will include how to plan a product's architecture, both the MVP and future version, how to lead a tech spikes into integrations and conduct a build vs buy reviews of third party providers. Head to thoughtbot.com/events to register, the event is June 17th 2 - 3 PM ET. Even if you can't make it, registering will get you on the list for the recording. CHRIS: We're the second-best. We're the second-best. Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Chris Toomey. STEPH: And I'm Steph Viccari. CHRIS: And together, we're here to share a bit of what we've learned along the way. So, Steph, what's new in your world? STEPH: I'm very happy to report that I picked up a treat from the store recently. So while I was in Boston and we were hanging out in person, we talked about Pop-Tarts because that always comes up as a debate, as it should. And then also Toaster Strudels came up, so I now have a package of Toaster Strudels, and those are legit. Pop-Tart or Toaster Strudel, I am team Toaster Strudel, which I know you're going to ask me about icing and if I put it on there, so go ahead. I'm going to pause. [laughs] CHRIS: It sounds like I don't even need to say anything. But yes, inquiring minds want to know. STEPH: I think that's also my very defensive response because yes, I put icing on my Toaster Strudel. CHRIS: How interesting. [laughs] STEPH: But it feels like a whole different class of pastry. So I'm very defensive about my stance on Pop-Tarts with no icing put Strudel with icing. CHRIS: A whole different class of pastry. Got it. Noted. Understood. So did you travel? Like, were these in your luggage that you flew back with? STEPH: [laughs] Oh no. They would be all gooey and melty. No, we bought them when we got back to North Carolina. Oh, that'd be a pro move; just pack little individual Strudels as your airplane snack. Ooh, I might start doing that now. That sounds like a great airplane snack. CHRIS: You got to be careful though if the icing, you know, if it's pressurized from ground level and then you get up there, and it explodes. And you gotta be careful. Or is it the reverse? It's lower pressure up in the plane. So it might explode. STEPH: [laughs] Either way, it might explode. CHRIS: Well, yeah. If you somehow buy a packet of icing that is sky icing that is at that pressure, and you bring it down, then...but if you take it up and down, I think it's fine. If you open it at the top, you might be in danger. If you open icing under the ocean, I think nothing's going to happen. So these are the ranges that we're playing with. STEPH: I will be very careful sky icing and probably pack two so that way I have a backup just in case. So if one explodes, we'll be like, all right, now I know what I'm working with and be more prepared for the next one. CHRIS: That's just smart. STEPH: I try to make smart travel decisions, Toaster Strudels on the go. Aside from travel treats and sky icing, I have some news regarding Planet Argon, who is a Ruby on Rails consultancy regarding their latest published this year's Ruby on Rails community survey results. And so they list a lot of fabulous different topics in there. And one of them includes a learning section that highlights most listened to podcasts in the Ruby on Rails community as well as blogs and some other resources. And Bike Shed is listed as the second most listened to podcast in the Ruby on Rails community, so whoo, golf clap. CHRIS: Fantastic. STEPH: And in addition to that, the thoughtbot blog got a really nice shout-out. So the thoughtbot blog is in the number two spot for the most visited blogs in the community. In the first spot is Ruby Weekly, which is like, you know, okay, that feels fair, that feels good. So it's really exciting for the thoughtbot blog because a lot of people work really hard on curating and creating that content. So that's wonderful that so many people are enjoying it. And then I should also highlight that for the podcast in first place is Remote Ruby, so congrats to Chris, Jason, and Andrew for grabbing that number one spot. And Brittany Martin, host of the Ruby on Rails Podcast, along with Brian Mariani, Jemma Issroff, and Nick Schwaderer, are in the number three spot. And some people say that Ruby is losing steam but look at all that content and all those highly ranked podcasts. I mean, we like Ruby so much we're spending time recording ourselves talking about it. So I say long live Ruby, long live Rails. CHRIS: Yes. Long live Ruby indeed. And yeah, it's definitely an honor to be on the list and to be amongst such other wonderful shows. Certainly big fans of the work of those other podcasts. We even did a joint adventure with them at one point, and that was a really wonderful experience, so yeah, honored to be on the list alongside them. And to have folks out there in the world listening to our tech talk and nonsense always nice to hear. STEPH: Yeah. You and I show up and say lots of silly things and technical things into the podcast. The true heroes are the ones that went and voted. So thank you to everybody who voted. That's greatly appreciated. It's really nice feedback. Because we get listener responses and questions, and those are wonderful because it lets us know that people are listening. But I have to say that having the survey results is also really nice. It lets us know people like the show. Oh, but I did go back and look at some of the previous stats because then I was like, huh, so I'm paying attention. I looked at this year's, and I was like, I wonder what last year's was or the year before that. And I think this survey comes out every two years because I didn't see one for 2021. But I did find the survey results for 2020, which we were in the number one spot for 2020, and Remote Ruby was in the second spot. So I feel like now we've got a really nice, healthy podcasting war situation going on to see who can grab the first spot. We've got two years, everybody, to see who [laughs] grabs the number one spot. That's a lot of prep time for a competition. CHRIS: Yeah, I feel like we should be like, I don't know, planning elaborate pranks on them or something like that now. Is that where this is at? It's something like that, I think. STEPH: I think so. I think this is where you put like sky frosting inside someone's suitcase, and that's the type of prank that you play. [laughs] CHRIS: The best of pranks. STEPH: We'll definitely put together a little task force. And we'll start thinking of pranks that we all need to start playing on each other for the podcasting wars that we're entering for the next few years. But anywho, what's going on in your world? CHRIS: Let's see, what's going on in my world? A fun thing happened recently. I had a chance to reflect back on some architectural choices that we've made in the Sagewell platform. And one of those specific choices is how we've approached building our native mobile apps. We made what some listeners may remember is an interesting set of choices. In particular, in Episode 328, which we'll include a link to in the show notes, I shared with you the approach that we're doing, which is basically like, Inertia is great, web user great. We like the web as a platform. What if we were to wrap it in a native shell and find this interesting and somewhat unique hybrid trade-off point? And so, at that point, we were building it. We had most of it built out, and things were going quite well. I think we maybe had the iOS app in the store and the Android app approaching the store or something like that. At this point, both apps have been released to the store, so they are live. Production users are signing in. It's wonderful. But I had a moment in the past couple of weeks to reassess or look at that set of choices and evaluate it. And thankfully, I'm happy with the choices that we've made. So that's good. But to get into the specifics, there were two things that happened that really, really framed the choice that we made, so one was we introduced a major new feature. We basically overhauled the first-run experience, the onboarding that users experience, and added a new, pretty fundamental facet to the platform. It's a bunch of new screens, and flows, and error states, and all of this complexity. And in the process, we iterated on it a bunch. Like, first, it looked like this, and then we changed the order of the screens and switched out the error messages, and et cetera, et cetera. And I'll be honest, we never even thought about the mobile apps. It just wasn't even a consideration. And interestingly, we did as a final check before going fully live and releasing this out to the full production audience; we did spot check it in the mobile apps, and it didn't work. But it didn't work for a very specific, boring, technical reason that we were able to resolve. It has to do with iframes and WebViews and embedded something, something. And we had to set a flag. Thankfully, it was solvable without a deploy of the native mobile apps. And otherwise, we never thought about the native apps. Specifically, we were able to add this fundamental set of features to our platform. And they just worked in native mobile. And they were the same as they roughly are if you're on a mobile WebView or if you're on a desktop web, you know, slightly different in terms of form factor. But the functionality was all the same. And critically, the error states and the edge cases and the flow, there's so much to think about when you're adding a nontrivial feature to an app. And the fact that we didn't have to consider it really spoke to the choice that we made here. And again, to name it, the choice that we made is we're basically just reusing the same WebViews, the same Rails controllers, and the same what are Svelte components under the hood but the same essentially view layer as well. And we are wrapping that in a native iOS. It's a Swift application shell, and on Android, it's a Kotlin application shell. But under the hood, it's the same web stuff. And that was really great. We just got these new features. And you know what? If we have to rip that whole set of functionality out, again, we won't need to deploy. We won't need to rethink it. Or, if we want to subtly tweak it, we can do that. If we want to think about feature flags or analytics, or error states or error reporting, all of this just naturally falls out of the approach that we took. And that was really wonderful. STEPH: That's super nice. I also love this saga of like, you made a choice, and then you're coming back to revisit and share how it's going. So as someone who's never done this before, in regards of wrapping an application in the manner that you have and then publishing it and distributing it that way, what does that process look like? Is this one of those like you run a command, and literally, it's going to wrap the application and then make it hostable on the different mobile app stores? Or what's that? Am I oversimplifying the process? What does that look like? CHRIS: I think there are a lot of platforms or frameworks I think would probably be the better word like Capacitor is something that comes to mind or Ionic or Expo. There are a handful of them that are a little more fully featured in what they provide. So you just point us at your React Views and whatnot, and we'll wrap that up, and it'll be great. But those are for, I may be overgeneralizing here, but my understanding is those are for more heavy client-side bundles that are talking to a common API. And so you're basically taking your same rich client-side application and bundling that up for reuse on the native app, the native app platforms. And so I think those do have some release to the store sort of thing. In our case, we went a little bit further with that integration wrapper thing that we built. So that is a thing that we maintain. We have a Sagewell iOS repo and a Sagewell Android repo. There's a bunch of Swift and Kotlin code, respectively, in each of them, and we deploy to the stores manually. We're doing that whole process. But critically, the code that is in each of those repositories is just the bridge glue code that says, oh, when this Inertia navigation event happens, I'm going to push a WebView to the navigation stack. And that's what that is. I'm going to render the tab bar of buttons at the bottom with the navigation elements that I get from the server. But it's very much server-driven UI, is the way that I would describe it. And it's wrapping WebViews versus actually having the whole client bundle wrapped up in the thing. It's unfortunately subtle to try and talk through on the radio, but yeah. [laughs] STEPH: You're doing great; this is helping. So if there's a change that you want to make, you go to the Rails application, and you make that change. And then do you need to update anything on that iOS repo? It sounds like you don't, which then you don't have to push a new update to the store. CHRIS: Correct. For the vast majority of things, we do not need to make any changes. It's very rare for us to deploy the iOS or the Android app is a different way to put it or to push new releases to the store. It happens we may want to add a new feature to the sort of bridge layer that we built, but increasingly, those are rare. And now it's basically like, yeah, we're just wrapping those WebViews, and it's going great. And again, to name it, it's a trade-off. It's an intentional trade-off that we've made. We're never going to have the richest, most deep platform integration, smooth experience. We are making a small trade-off on that front. But given where we're at as an organization, given how early we are, how much iteration and change, we chose an architecture that optimizes for that change. And so again, like what you just said, yeah, I can...you know how it's really nice to be able to deploy six times a day on a web app, and that's a very straightforward thing to do? It is not so straightforward in the native mobile world. And so, we now have afforded ourselves the ability to do that. But critically, and this is the fun part in my mind, have the trade-offs in the controls. So if we were just like, it's just a WebView, and that's it, and we put it in the stores, and we're done, that is too far of an extreme in my mind. I think the performance trade-offs, the experience trade-offs, it wouldn't feel like a native app like in a deep way, in a problematic way. And so as an example, we have a navigation bar at the top of our app, particularly on iOS, that is native iOS navigation. And we have a tab bar at the bottom, which is native tab UI element. I forget actually what it's called, but it's those elements. And we hide the web application navigation when we're in the mobile context. So we actually swap those out and say, like, let's actually promote these to formal native functionality. We also, within our UI on the web, have a persistent button in the top right corner of your screen that says, "Need help? Reach out to your retirement advocate." who is the person that you get to work with. You can send questions, et cetera, et cetera. It's this little help sidebar drawer thing that pops out. And we have that as a persistent HTML button in the top corner of the web frame. But when we're on native, we push that up as a distinct element in the native UI section. And then again, the bridge that I'm talking about allows for bi-directional communication between the JavaScript side and the native side or the native side and the JavaScript side. And so it's those sorts of pieces that have now afforded us all of the freedom to tinker, and we don't need to re-release where we're like, oh, we want to add a new weird button that does a thing in the WebView when you click on a button outside the WebView. We now just have that built-in. STEPH: Yeah, I really like the flexibility that you're describing. When you promoted those elements to be more native-friendly so, like the navigation or the footer or the little get help chat, is that something that then your team implemented in like the iOS or the Kotlin repo? Okay, I see you nodding, but other people can't see that, so...[laughs] CHRIS: Yeah. I was going to also say the words, but yes, those are now implemented as native parts. So the thing that we built isn't purely agnostic decoupled. It is Sagewell-specific; a lot of it is low-level. Like, let's say we want to wrap an Inertia app in a native mobile wrapper. Like, 90% of the code in it is that, but then there are little bits that are like, and put a button up there. And that button is the Sagewell button. And so it's not entirely decoupled from us. But it mostly is this agnostic bridge to connect things together. STEPH: Yeah, the way you're describing it sounds really nice in terms of you're able to get out the app quickly and have a mobile app quickly that works on both platforms, and then you're still able to deploy changes without having to push that. That was always my biggest mental, or emotional hurdle with the idea of mobile development was the concept of that you really had to batch everything together and then submit it for review and approval and then get it released. And then you got to hope people then upgrade and get the newest version. And it just felt like such a process, not that I ever did much of it. This was all just even watching like the mobile team and all the work that they had to do. And I had sympathy pains for them. But the fact that this approach allows you to avoid a lot of that but still have some nice, customized, more native elements. Yeah, I'm basically just recapping everything you said because I like all of it. CHRIS: Well, thank you, friend. Like I said, I've really enjoyed it, and similar to you, I'm addicted to the feedback loop of the web. It's beautiful. I can deploy ten times or however many I want. Anytime I want, I can push out a new version. And that ability to iterate, to test, to explore, to tweak, to not have to do as much formal testing upfront because I'm terrified that if a bug sneaks out, then, it'll take me two weeks to address it; it just is so, so freeing. And so to give that up moving into a native context. Perhaps I'm fighting too hard to hold on to my dream of the ability to rapidly iterate. But I really do believe in that and especially for where we're at as an organization right now. But, and a critical but here, again, it's a trade-off like anything else. And recently, I happened to be out about in the town, and I decided, oh, you know what? Let me open up the app. Let me see what it's like. And I wasn't on great internet. And so I open the app, and it loads because, you know, it's a native app, so it pops up. But then the thing that actually happened is a loading spinner in the middle of the screen and sort of a gray nothing for a little while until the server request to fetch the necessary UI elements to render the login screen appeared. And that experience was not great. In particular, that experience is core to the experience of using the app every single time. Every time you use it, you're going to have a bad time because we're re-downloading that UI element. And there's caching, and there's things that could happen there to help with that. But fundamentally, that experience is going to be a pretty common one. It's the first thing that you experience when you're opening the app. And so I noticed that and I chatted with the team, and I was like, hey, I feel like this is actually something that fixing this I think would really fundamentally move us along that spectrum of like, we've definitely made some trade-offs here. But overall, it feels snappy and like a native app. And so, we opted to prioritize work on a native login screen for both platforms. This also allows us to more deeply integrate. So particularly, we're going to get biometric logins like fingerprints or face scans, or whatever it is. But critically, it's that experience of like, I open the Sagewell native app on my iOS phone, and then it loads immediately. And then I show it my face like we do these days, and then it opens up and shows me everything that I want to see inside of it. And it's that first-run experience that feels worth the extra effort and the constraints. Because now that it's native mobile, that means in order to change it, we have to do a deploy, not a deploy, release; that's what they call it in the native world. [laughs] You can tell I'm well-versed in this ecosystem. But yeah, we're now choosing that trade-off. And what I really liked about this sort of set of things like the feature that we were able to just accidentally get for free on native because that's how this thing is built. And then likewise, the choice to opt into a fully native login screen like having that lever, having that control over I'm going to optimize for iteration generally, but where it's important, we want to optimize for performance and experience. And now we have this little slider that we can go back and forth. And frankly, we could choose to screen by screen just slowly replace everything in the app with true native WebViews backed by APIs. And we could Ship of Theseus style replace every element of the app with true native mobile things until none of the old bridge code exists. And our users, in theory, would never know. Having that flexibility is really nice given the trade-off and the choice that we've made. STEPH: You said a word there that I missed. You said ship something style. CHRIS: Ship of Theseus. STEPH: What is that? CHRIS: It's like an old biblical story, I want to say, but it's basically the idea of, like, you have the ship. And then some boards start to rot out, so replace those boards. And then the mast breaks, you replace the mast. And slowly, you've replaced every element on the ship. Is it still the same ship at that point? And so it's sort of a philosophical question. So if we replace every single view in this app with a native view, is it still the same map? Philosophers will philosophize about it forever, but whatever. As long as we get to keep iterating and shipping software, then I'm happy. STEPH: [laughs] Y'all philosophize. That's that word, right? CHRIS: Yeah. STEPH: And do your philosopher thing. We'll just keep building and shipping. CHRIS: I don't know if I pronounced it right. It's like either Theseus or Theseus, and I'm sure I said the wrong one. And now that I've said the other, I'm sure both of them are wrong somehow. It's like a USB where there's up and down, and yet somehow it takes three tries. So anyway, I may have mispronounced it, and I may be misattributing it, but that's the idea I was going for. STEPH: Well, given I wasn't even familiar with the word until just now, I'm going to give both pronunciations a thumbs up. I also really like how you decided that for the login screen, that's the area that you don't want people to wait because I agree if you're opening an application or opening...maybe it's the first time, maybe it's the 100th time. Who knows? But that feels important. Like, that needs to be snappy. I need to know it's responsive. And it builds trust from the minute that I clicked on that application. And if it takes a long time, I just immediately I'm like, what are y'all doing? Are y'all real? Do you know what you're doing over there? So I like how you focused on that experience. But then once I log in, like if something is slow to log me in, I will make up excuses for the application all day where I'm like, well, you know, maybe it's my connection. It's fine. I can wait for the next screen to load. That feels more reasonable. And it doesn't undermine my trust nearly as much as when I first click on the app. So that feels like a really nice trade-off as well, or at least a nice area that you've improved while still having those other trade-offs and benefits that you mentioned. CHRIS: To highlight it, you used a phrase there which I really liked. Like, it's building trust. If something's a little bit off in that first run experience every single time, then it kind of puts a question in the back of your head, maybe not even consciously. But you're just kind of looking at it, and you're like, what are you doing there? What are you up to, friend? Humans say to the apps they use on their phone. That's normal, right? When you talk... But to name it, we've also done a round of performance work throughout the app. And so there are a couple of layers to it. But it was work that we had planned for a while, but we kept deferring. But now that we're seeing more usage of the native apps, the native apps experience the same surface area of performance stuff but all the more so because they may be on degraded network connections, et cetera. And so this is another example where this whole thing kind of pays off. The performance work that we did affects everything. It affects the web. It's the same under the hood. It's let's reduce the network requests that we're making in the payloads that we're sending, particularly the network requests to upstream things, so like the banking partner that we're using and those APIs, like, collating all the data to then render the screen. Because of Inertia, we only have a single sort of back and forth conversation via the API as opposed to I think it's pretty common to have like seven different APIs and four different spinners on the screen. We're not doing that, none of that on my watch. [chuckles] But we minimize the background calls to the other parties that we're integrating with. And then, we reduce the payload of data that we're sending on each request. And each of those were like, we had to think about things and tweak and poke, but again it's uniform. So mobile web has that now, desktop web has that now. Android, iOS, they all just inherited it sort of that just happened one day without a deploy or release, without a release of either of the native mobile apps. We did deploy to the web to make that happen, but that's easy. I can do that a bunch of times a day. One last thing I want to share as we're on this topic of trade-offs and levers, there was a really great conference talk that I watched recently, which was Ryan Florence of remix.run also React Router fame if you're familiar with him from that. But he was talking about the most recent version of Remix, which is their meta framework on top of React. But they've done some really interesting stuff around processing data, fetching data, when and how to sequence that. And again, that thing that I talked about of nine different loading spinners on the screen, Remix is taking a very different approach but is targeting that same thing of like, that's not great for user experience. Cumulative layout shift being the actual number that you can monitor for this. But in that talk, there are features that they've added to Remix as a framework where you can just decide, like, do we wait for this or do we not? Do we make sure we have all of the data, or do we say, you know what? Actually, this is going to be below the fold. So it's okay to defer loading this until after we send down the first payload. And then we'll kick in, and we'll do it from the client-side. But it's this wonderful feature of the framework that they're adding in where there's basically just a keyword that you can add to sort of toggle that behavior. And again, it's this idea of like trade-offs. Are we okay with more layout shift, or are we okay with more waiting? Which is it that we're going to optimize for? And I really love that idea of putting that power very simply in the hands of the developers to make those trade-off decisions and optimize over time for what's important. So we'll share a link to that talk in the show notes as well. But it was very much in the same space of like, how do I have the power to decide and to change my mind over time? That's what I want. But yeah, with that, I think that's enough of me updating on the mobile app. I'll continue to share as new things happen. But again, I'm at this point very happy with where we're at. So yeah, it's been fun. But yeah, what else is up in your world? STEPH: I have a dear Gerrit message that I wrote earlier, so I want to share that with you. Gerrit is the system that we're using for when we push up code changes that then manages very similar in the competitive space of like GitHub and GitLab, and Bitbucket. And so the team that I'm working with we are using Gerrit. And Gerrit and I, you know, we get along for the most part. We've managed to have a working relationship. [chuckles] But this week, I wrote my dear Gerrit letter is that I really miss being able to tell a story with my commit messages. That is the biggest pain that I'm feeling right now. So for anyone that's less familiar or if you already are familiar with Gerrit, each change that Gerrit shows represents a single commit that's under review. And each change is identified by a Change-Id. So the basic concept of Gerrit is that you only have one commit per review. So if you were to translate that to GitHub terminology, every pull request is only going to have one commit, and so you really can't push up multiple. And so, where that has been causing me the most pain is I miss being able to tell a story. So like even simple stories that are like, hey, I removed something that's not used. I love separating that type of stuff into its own commit just so then people can see that as they're going through review. Now, before I merge, I'm likely to squash, and that doesn't feel important that it needs to be its own commit. That's really just for the reviewer so they can follow along for the changes. But the other one, I can slowly get over that one. Because essentially, the way I get around that is then when I do push up my code for review, is I then go through my change request, and then I just add comments. So I will highlight that line and say, "Hey, I'm removing this because it's not in use." And so, I found a workaround for that one. But the one I haven't found a workaround for is that I don't push up my local work very often because I love having lots of local, tiny, green commits so that way I can know the progress that I'm at. I know where I'm headed. Also, I have a safe space to roll back to, but then that means that I may have five or six commits that I have locally, but I haven't pushed up somewhere. And that is bothering me more and more hour by hour the more I think about it that I can't push stuff up because it makes me nervous. Because, I mean, usually, at least by the end of the day, I push everything up, so it's stored somewhere. And I don't have to worry about that work disappearing. Now I am working on a dev machine. So there is that aspect of it's technically...it's not even on my local machine. It is stored somewhere that I should still be able to access. CHRIS: What's a dev machine? The way you're saying it, it sounds like it's a virtual machine, not like a laptop. But what's a dev machine? STEPH: Good question. So the dev machine is a remote server or remote machine that then I am accessing, and then that's where I'm performing. That's where I'm writing all of my work. And then that's also kind of the benefit is everything is not local; it's controlled by the team. So then that also means that other teams, other individuals can help set up these environments for future developers. So then you have that consistency across everyone's working with the same Rails version, or gems, or has access to the same tools. So in that sense, my work isn't just on my laptop because then that would really worry me because then I've got nowhere...it's not backed up anywhere. So at least it is somewhere it's being stored that then could be accessed by someone. So actually, now, as I'm talking this through, that does help alleviate my concern about this a bit. [laughs] But I still miss it; I still miss being able to just push up my work and then have multiple commits. And I looked into it because I was like, well, maybe I'm misunderstanding something about Gerrit, and there's a way around this. And that's still always a chance. But from the research that I've done, it doesn't seem to be. And there are actually two very fiery takes that I saw that I have to share because they made me laugh. When I was Googling, the question of like, "Can I push up multiple commits to one single Gerrit CR? Or is there just a way to, like, can I have this concept of like a branch and then I have many commits, but then I turn it into one CR? Whatever the world would give me. What do they have? [laughs] I'm laughing just looking at this now. One of the responses was, have you tried squashing your commits into one commit? And I was like, [laughs] "Yeah, that's not what I had in mind, but sure." And then the other one, this is the more fiery take. They were very defensive about Gerrit, and they wrote that "People who don't like Gerrit usually just hack shit together. They cut corners and love squashing commits or throwing away history. And those people hate Gerrit. Developers who care love it. It's definitely possible and easy to produce agile software." And I just...that made me laugh. I was like, cool, I'm a developer that cuts corners and loves squashing commits. [laughs] CHRIS: So you don't care is what that take says. STEPH: I'm a developer who does not care. CHRIS: You know, Steph, I've worked with you for a while. And I've been looking for the opportunity to have this hard conversation with you. But I just wish you cared a little more about the software that you're writing, about the people that you're working with, about the commits that you're authoring. I just see it in every facet of your work. You just don't care. To be very clear for anyone listening at home, that is the deepest of sarcasm that I can make. Steph cares so very much. It's one of the things that I really enjoy about you. STEPH: I mean, we had the episode about toxic traits. This would have been the perfect time to confront me about my lack of caring about software and the processes that we have. So winding down on that saga, it seems to be the answer is no, friend; I cannot push up multiple commits. Oh, I tried to hack it. I am someone that tries to hack shit together because I tried to get around it just to see what would happen. [laughs] Because the docs had suggested that each change is identified by a Change-Id. And I was like, hmm, so what if there were two commits that had the same Change-Id, would Gerrit treat those as patch sets? Because right now, when you push up a change, you can see all the different patch sets, so that's nice. So that's a nice feature of Gerrit as you can see the history of, like, someone pushed up this change. They took in some feedback. They pushed up a new change. And so that history is there for each push that someone has provided. And I wondered maybe if they had the same Change-Id that then the patch sets would show the first commit and then the second commit. And so I manually altered the commits two of them to reference the same Change-Id. And I have to say, Gerrit was on to me because they gave me a very nice error message that said, "Same Change-Id and multiple changes. Squash the commits with the same Change-Ids or ensure Change-Ids are unique for each commit. And I thought, dang, Gerrit, you saw me coming. [laughs] So that didn't work either. I'm still in a world of where I now wait. I wait until I'm ready for someone to review stuff, and I have to squash everything, and then I go comment on my CRs to help out reviewers. CHRIS: I really like the emotional backdrop that you provided here where you're spending a minute; you're like, you know what? Maybe it's me. And there's the classic Seymour Skinner principle from The Simpsons. Am I out of touch? No, it's the children who are wrong. [laughs] And I liked that you took us on a whole tour of that. You're like, maybe it's me. I'll maybe read up. Nope, nope. So yeah, that's rough. There's a really interesting thing of tools constraining you. And then sometimes being like, I'm just going to yield control and back away and accept this thing that doesn't feel right to me. Like, Prettier does a bunch of stuff that I really don't like. It shapes code in a way, and I'm just like, no, that's not...nope, you know what? I've chosen to never care about this again. And there's so much utility in that choice. And so I've had that work out really well. Like with Prettier, that's a great example whereby yielding control over to this tool and just saying, you know what? Whatever you produce, that is our format; I don't care. And we're not going to talk about it, and that's that. That's been really useful for myself and for the teams that I'm on to just all kind of adopt that mindset and be like, yeah, no, it may not be what I would choose but whatever. And then we have nice formatted code; it's great. It happens automatically, love it. But then there are those times where I'm like; I tried to do that because I've had success with that mindset of being like, I know my natural thing is to try and micromanage and control every little bit of this code. But remember that time where it worked out really well for me to be like, I don't care, I'm just going to not care about this thing? And I try to not care about some stuff, which it sounds like that's what you're doing right here. [laughs] And you're like, I tried to not care, but I care. I care so much. And now you're in that [chuckles] complicated space. So I feel for you, Steph. I'm sorry you're in that complicated space of caring so much and not being able to turn that off [laughs] nor configure the software to do the thing you want. STEPH: I appreciate it. I should also share that the team that I'm working with they also don't love this. Like, they don't love Gerrit. So when I shared in the Slack channel my dear Gerrit message, they're both like, "Yeah, we feel you. [laughs] Like, we're in the same spot," which was also helpful because I just wanted to validate like, this is the pain I'm feeling. Is someone else doing something clever or different that I just don't know about? And so that was very helpful for them to say, "Nope, we feel you. We're in the same spot. And this is just the state that we're in." I think they have started transitioning some other repos over to GitLab and have several repos in Gitlab, but this one is still currently using Gerrit. So they very much commiserate with some of the things that I'm feeling and understand. And this does feel like one of those areas where I do care deeply. And frankly, this is one of those spaces that I do care about, but it's also like, I can work around it. There are some reasonable things that I can do, and it's fine as we just talked through. Like, the fact that my commits are not just locally on my machine already makes me feel better now that I've really processed that. So there are lower risks. It is more of just like a workflow. It's just, you know, it's crushing my work vibe. CHRIS: Harshing your buzz. STEPH: In the great words of Queen Elsa, I gotta let it go. This is the thing I'm letting go. So that's kind of what's going on in my world. What else is going on in your world? CHRIS: Well, first and foremost, fantastic reference and segue. I really liked that. But yeah, let's see, [laughs] what else is going on in my world? We had an interesting thing happen last week. So we had an outage on the platform last week. And then we had an incident review today, so a formal sort of post-mortem incident review. There are a couple of different names that folks have given to these. But this is a practice that we want to build within our engineering culture is when stuff goes wrong, we want to make sure that we have meaningful conversations around to try to address the root causes. Ideally, blameless is a word that gets used often in this context. And I've heard folks sort of take either side of that. Like, it's critical that it's blameless so that it doesn't feel like it's an attack. But also, like, I don't know, if one person did something, we should say that. So finding that gentle middle ground of having honest, real conversations but in a context of safety. Like, we're all going to make mistakes. We're all going to ship bugs; let's be clear about that. And so it's okay to sort of...anyway, that's about the process. We had an outage. The specific outage was that we have introduced a new process. This is a Sidekiq process to work off a specific queue. So we wanted that to have discrete treatment. That had been running, and then it stopped running; we still don't know why. So we never got to the root-root cause. Well, we know what the mechanism was, which was the dyno count for that process was at zero. And so, eventually, we found a bunch of jobs backed up in the Sidekiq admin. We're like, that's weird. And then, we went over to Heroku's configuration dashboard. And we saw, huh, that's weird. There are zero dynos processing this. That wasn't true yesterday. But unfortunately, Heroku doesn't log or have an audit trail around changes to those process counts. It's just not available. So that's unfortunate. And then the actual question of like, how did this happen? It probably had to be someone on the team. So there is like, someone did a thing. But that is almost immaterial because, again, people are going to do things, bugs will get shipped, et cetera. So the conversation very quickly turned to observability and understanding. I think we've done a pretty good job of instrumenting error reporting and being quite responsive to that, making sure the signal-to-noise ratio is very actionable. So if we see a bug or a Sentry alert come through, we're able to triage that pretty quickly, act on it where it is a real bug, understand where it's a bit of noise in the system, that sort of thing. But in this case, there were no errors. There was no Sentry. There was nothing; there was the absence of something. And so it was this really interesting case of that's where observability, I think, can really come in and help. So the idea of what can we do here? Well, we can monitor the count of jobs backed up in Sidekiq queue. That's one option. We could do some threshold alerting around the throughput of processed events coming from this other backend. There are a bunch of different ways, but it basically pushed us in the direction of doubling down and reinforcing the foundation of our observability within the platform. So we're just kicking that mini-project off now, but it is something we're like, yeah, we feel like we could add some here. In particular, we recently added Datadog to the stack. So we now have Datadog to aggregate our logs and ideally do some metric analysis, those sort of things, build some dashboards, et cetera. I haven't explored Datadog much thus far. But my sense is they've got the whiz-bang things that we need here. But yeah, it was an interesting outage. That wasn't fun. The incident conversation was actually a good conversation as a team. And then the outcome of like, how do we double down on observability? I'm actually quite excited for. STEPH: This is a fun moment for me because I have either joined teams that didn't have Datadog or have any of that sort of observability built into their system or that sort of dashboard that people go to. Or I've joined teams, and they already have it, and then nobody or people rarely look at it. And so I'm always intrigued between like what's that catalyst that then sparked a team to then go ahead and add this? And so I'm excited to hear you're in that moment of like, we need more observability. How do we go about this? And as soon as you said Datadog, I was like, yeah, that sounds nice because then it sounds like a place that you can check on to make sure that everything is still running. But then there's still also that manual process where I'm presuming unless there's something else you have in mind. There's still that manual process of someone has to check the dashboard; someone then has to understand if there's no count, no squiggly lines, that's a bad thing and to raise a concern. So I'm intrigued with my own initial reaction of, like, yeah, that sounds great. But now I'm also thinking about it still adds a lot of...the responsibility is still on a human to think of this thing and to go check it. Versus if there's something that gets sent to someone to alert you and say like, "Hey, this queue hasn't been processed in 48 hours. There may be a concern that actually feels nicer." It feels safer. CHRIS: Oh yeah, definitely. I think observability is this category of tools and workflows and whatnot. But I think what you're describing of proactive alerting that's the ideal. And so it would be wonderful if I never had to look at any of these tools ever. And I just knew if I got, let's say, it's PagerDuty connected up whatever, and I got a push notification from PagerDuty saying, "Hey, go look at this thing." That's all I ever need to think about. It's like, well, I haven't gotten a PagerDuty in a while, so everything must be fine, and having a deep trust in that. Similar to like, if we have a great test suite and it's green, I feel confident deploying the sort of absence of an alert being the thing that I can trust. But right now, we're early enough in this journey that I think what we need to do is stand up a bunch of these different graphs and charts and metric analysis and aggregations and whatnot, and then start to squint at it for a while and be like, which of these would I be really concerned if it started to wibble? And then you can figure the alerting around said wibble rate. And that's the dream. That's where we want to get to, but I think we've got to crawl, walk, run on this. So it'll be an adventure. This is very much the like; we're starting a thing. I'll tell you about it more when we've done it. But what you're describing is exactly what we want to get to. STEPH: I love wibble rate. That's my new measurement I'm going to start using for everything. It's funny, as you're bringing this up, it's making me think about the past week that Joël Quenneville and I have had with our client work. Because a somewhat similar situation came up in regards where something happened, and something was broken. And it seemed it was hard to define exactly what moment caused that to break and what was going on. But it had a big impact on the team because it essentially meant none of the bills were going through. And so that's a big situation when you got 100-plus people that are pushing up code and expecting some of the build processes to run. But it was one of those that the more we dug into it, the more it seemed very rare that it would happen. So, in this case, as a sort of a juxtaposition to your scenario, we actually took the opposite approach of where we're like; this is rare. But we did load up a lot of contexts. Actually, I was thinking back to the advice that you gave me in a previous episode where I was talking about at what point do you dig in versus try to stay at surface level? And this was one of those, like, we've spent a couple of days on getting context for this and understanding. So it felt really important and worthwhile to then invest a little bit more time to then document it. But then we still went with the simplest approach of like, this is weird. It shouldn't happen again. We think we understand it but then let's add a little bit of documentation or wiki page around like, hey, if you do run into this, here are some steps that will fix everything. And then, if you need to use this, let somebody know because this is so odd it shouldn't happen. So we took that approach in this case where we didn't increase the observability. It was more like we provided a fire extinguisher very close to the location in case it happens. And so that way, it's there should the need arise, but we're hoping it just never gets used. We're also in the process of changing how a lot of that logic works. So we didn't really want to optimize for observability into a system that is actively being changed because it should look very different in upcoming months. But overall, I love the conversations that you bring about observability, and I'm excited to hear about what wibble rates you decide to add to your Datadog dashboard. CHRIS: There's a delicate art and science to the selection of the wibble rates. So I will certainly report back as we get into that work. But with that, shall we wrap up? STEPH: Let's wrap up. CHRIS: The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

The Bike Shed
341: Fundamentals and Weird Stuff

The Bike Shed

Play Episode Listen Later Jun 7, 2022 35:27


Steph and Chris are recording together! Like, in the same room, physically together. Chris talks about slowly evolving the architecture in an app they're working on and settling on directory structure. Steph's still working on migrating unit tests over to RSpec. They answer a listener question: "As senior-level developers, how do you set goals to ensure that you keep growing?" This episode is brought to you by BuildPulse (https://buildpulse.io/bikeshed). Start your 14-day free trial of BuildPulse today. Faking External Services In Tests With Adapters (https://thoughtbot.com/blog/faking-external-services-in-tests-with-adapters) Testing Third-Party Interactions (https://thoughtbot.com/blog/testing-third-party-interactions) Jen Dary - On Future Goals (https://www.beplucky.com/on-future-goals/) Charity Majors - The Engineer Manager Pedulum (https://charity.wtf/2017/05/11/the-engineer-manager-pendulum/) Charity Majors Bike Shed Episode (https://www.bikeshed.fm/302) Become a Sponsor (https://thoughtbot.com/sponsorship) of The Bike Shed! Transcript: STEPH: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Steph Viccari. CHRIS: And I'm Chris Toomey. STEPH: And together, we're here to share a bit of what we've learned along the way. So, hey, Chris, what's new in your world? CHRIS: What is new in my world? Actually, this episode feels different. There's something different about it. I can't quite put my finger on it. I think it may be that we're actually physically in the same room recording for the first time in two years and a little bit more, which is wild. STEPH: I can't believe it's been that long. I feel like it wasn't that long ago that we were in The Bike Shed...oh, I said The Bike Shed studio. I'm being very biased. Our recording studio [laughs] is the more proper description for it. Yeah, two and a half years. And we tried to make this happen a couple of months ago when I was visiting Boston, and then it just didn't work out. But today, we made it. CHRIS: Today, we made it. Here we are. So hopefully, the audio sounds great, and we get all that more richness in conversation because of the physical in-person manner. We're trying it out. It'll be fun. But let's see, to the normal tech talk and nonsense, what's new in my world? So we've been slowly evolving the architecture in the app that we're working on. And we settled on something that I kind of like, so I wanted to talk about it, directory structure, probably the most interesting topic in the world. I think there's some good stuff in here. So we have the normal stuff. There are app models, app controllers, all those; those make sense. We have app jobs which right now, I would say, is in a state of flux. We're in the sad place where some things are application records, and some things are Sidekiq workers. We have made the decision to consolidate everything onto Sidekiq workers, which is just strictly more powerful as to the direction we're going to go. But for right now, I'm not super happy with the state of app jobs, but whatever, we have that. But the things that I like so we have app commands; I've talked about app commands before. Those are command objects. They use dry-rb do notation, and they allow us to sequence a bunch of things that all may fail, and we can process them all in a much more reasonable way. It's been really interesting exploring that, building on it, introducing it to new developers who haven't worked in that mode before. And everyone who's come into the project has both picked it up very quickly and enjoyed it, and found it to be a nice expressive mode. So app commands very happy with that. App queries is another one that we have. We've talked about this before, query objects. I know we're a big fan. [laughs] I got a golf clap across the room here, which I could see live in person. It was amazing. I could feel the wind wafting across the room from the golf clap. [chuckles] But yeah, query objects, they're fantastic. They take a relation, they return a relation, but they allow us to build more complex queries outside of our models. The new one, here we go. So this stuff would all normally fall into app services, which services don't mean anything. So we do not have an app services directory in our application. But the new one that we have is app clients. So these are all of our HTTP clients wrapping external third parties that we're interacting with. But with each of them, we've taken a particular structure, a particular approach. So for each of them, we're using the adapter pattern. There's a blog post on the Giant Robots blog that I can point to that sort of speaks to the adapter pattern that we're using here. But basically, in production mode, there is an HTTP backend that actually makes the real requests and does all that stuff. And in test mode, there is a test backend for each of these clients that allows us to build up a pretty representative fake, and so we're faking it up before the HTTP layer. But we found that that's a good trade-off for us. And then we can say, like, if this fake backend gets a request to /users, then we can respond in whatever way that we want. And overall, we found that pattern to be really fantastic. We've been very happy with it. So it's one more thing. All of them were just gathering in-app models. And so it was only very recently that we said no, no, these deserve their own name. They are a pattern. We've repeated this pattern a bunch. We like this pattern. We want to even embrace this pattern more, so long live app clients. STEPH: I love it. I love app clients. It's been a while since I've been on a project that had that directory. But there was a greenfield project that I was working on. I think it might have been I was working with Boston.rb and working on giving them a new site or something like that and introduced app clients. And what you just said is perfect in terms of you've identified a pattern, and then you captured that and gave it its own directory to say, "Hey, this is our pattern. We've established it, and we really like it." That sounds awesome. It's also really nice as someone who's new to a codebase; if I jump in and if I look at app clients, I can immediately see what are the third parties that we're working with? And that feels really nice. So yeah, that sounds great. I'm into it. CHRIS: Yeah, I think it really was the question of like, is this a pattern we want to embrace and highlight within the codebase, or is this sort of a duplication but irrelevant like not really that important? And we decided no, this is a thing that matters. We currently have 17 of these clients, so 17 different third-party external things that we're integrating with. So for someone who doesn't really like service-oriented architecture, I do seem to have found myself in a place. But here we are, you know, we do what we have to with what we're given. But yes, 17 and growing our app clients. STEPH: That is a lot. [laughs] My eyes widened a bit when you said 17. I'm curious because you highlighted that app services that's not really a thing. Like, it doesn't mean anything. It doesn't have the same meaning of the app queries directory or app commands or app clients where it's like, this is a pattern we've identified, and named, and want to propagate. For app services, I agree; it's that junk drawer. But I guess in some ways...well, I'm going to say something, and then I'm going to decide how I feel about it. That feels useful because then, if you have something but you haven't established a pattern for it, you need a place for it to go. It still needs to live somewhere. And you don't necessarily want to put it in app models. So I'm curious, where do you put stuff that doesn't have an established pattern yet? CHRIS: It's a good question. I think it's probably app models is our current answer. Like, these are things that model stuff. And I'm a big believer in the it doesn't need to be an application record-backed object to go on app models. But slowly, we've been taking stuff out. I think it'd be very common for what we talk about as query objects to just be methods in the respective application record. So the user record, as a great example, has all of these methods for doing any sort of query that you might want to do. And I'm a fan of extracting that out into this very specific place called app queries. Commands are now another thing that I think very typically would fall into the app services place. Jobs naming that is something different. Clients we've got serializers is another one that we have at the top level, so those are four. We use Blueprinter within the app. And again, it's sort of weird. We don't really have an API. We're using Inertia. So we are still serializing to JSON across the boundary. And we found it was useful to encapsulate that. And so we have serializers as a directory, but they just do that. We do have policies. We're using Pundit for authorization, so that's another one that we have. But yeah, I think the junk drawerness probably most goes to app models. But at this point, more and more, I feel like we have a place to put things. It's relatively clear should this be in a controller, or should this be in a query object, or should this be in a command? I think I'm finding a place of happiness that, frankly, I've been searching for for a long time. You could say my whole life I've been searching for this contented state of I think I know where stuff goes in the app, mostly, most of the time. I'm just going to say this, and now that you've asked the excellent question of like, yeah, but no, where are you hiding some stuff? I'm going to open up models. Next week I'm going to be like, oh, I forgot about all of that nonsense. But the things that we have defined I'm very happy with. STEPH: That feels really fair for app models. Because like you said, I agree that it doesn't need to be ActiveRecord-backed to go on app models. And so, if it needs to live somewhere, do you add a junk drawer, or do you just create app models and reuse that? And I think it makes a lot of sense to repurpose app models or to let things slide in there until you can extract them and let them live there until there's a pattern that you see. CHRIS: We do. There's one more that I find hilarious, which is app lib, which my understanding...I remember at one point having one of those afternoons where I'm just like, I thought stuff works, but stuff doesn't seem to work. I thought lib was a directory in Rails apps. And it was like, oh no, now we autoload only under the app. So you should put lib under app. And I was just like, okay, whatever. So we have app lib with very little in it. [laughs] But that isn't so much a junk drawer as it is stuff that's like, this doesn't feel specific to us. This goes somewhere else. This could be extracted from the app. But I just find it funny that we have an app lib. It just seems wrong. STEPH: That feels like one of those directories that I've just accepted. Like, it's everywhere. It's like in all the apps that I work in. And so I've become very accustomed to it, and I haven't given it the same thoughtfulness that I think you have. I'm just like, yeah, it's another place to look. It's another place to go find some stuff. And then if I'm adding to it, yeah, I don't think I've been as thoughtful about it. But that makes sense that it's kind of silly that we have it, and that becomes like the junk drawer. If you're not careful with it, that's where you stick things. CHRIS: I appreciate you're describing my point of view as thoughtfulness. I feel like I may actually be burdened with historical knowledge here because I worked on Rails apps long, long ago when lib didn't go in-app, and now it does. And I'm like, wait a minute, but like, no, no, it's fine. These are the libraries within your app. I can tell that story. So, again, thank you for saying that I was being thoughtful. I think I was just being persnickety, and get off my lawn is probably where I was at. STEPH: Oh, full persnicketiness. Ooh, that's tough to say. [laughs] CHRIS: But yeah, I just wanted to share that little summary, particularly the app clients is an interesting one. And again, I'll share the adapter pattern blog post because I think it's worked really well for us. And it's allowed us to slowly build up a more robust test suite. And so now our feature specs do a very good job of simulating the reality of the world while also dealing with the fact that we have these 17 external situations that we have to interact with. And so, how do you balance that VCR versus other things? We've talked about this a bunch of times on different episodes. But app clients has worked great with the adapter pattern, so once more, rounding out our organizational approach. But yeah, that's what's up in my world. What's up in your world? STEPH: So I have a small update to give. But before I do, you just made me think of something in regards to that article that talks about the adapter pattern. And there's also another article that's by Joël Quenneville that's testing third-party interactions. And he made me reflect on a time where I was giving the RSpec course, and we were talking about different ways to test third-party interactions. And there are a couple of different ways that are mentioned in this article. There are stub methods on adapter, stub HTTP request, stub request to fake adapter, and stub HTTP request to fake service. All that sounds like a lot. But if you read through the article, then it gives an example of each one. But I've found it really helpful that if you're in a space that you still don't feel great about testing third-party interactions and you're not sure which approach to take; if you work with one API and apply all four different strategies, it really helps cement how to work through that process and the different benefits of each approach and the trade-offs. And we did that during the RSpec course, and I found it really helpful just from the teacher perspective to go through each one. And there were some great questions and discussions that came out of it. So I wanted to put that plug out there in the world that if you're struggling testing third-party interactions, we'll include a link to this article. But I think that's a really solid way to build a great foundation of, like, I know how to test a third-party app. Let me choose which strategy that I want to use. Circling back to what's going on in my world, I am still working on migrating unit tests over to RSpec. It's a thing. It's part of the work that I do. [laughs] I can't say it's particularly enjoyable, but it will have a positive payoff. And along that journey, I've learned some things or rediscovered some things. One of them is read expectations very carefully. So when I was migrating a test over to RSpec, I read it as where we expected a record to exist. The test was actually testing that a record did not exist. And so I probably spent an hour understanding, going through the code being like, why isn't this record getting created like I expect it to? And I finally went back, and I took a break, and I went back. And I was like, oh, crap, I read the expectation wrong. So read expectations very carefully. The other one...this one's not learned, but it is reinforced. Mystery Guests are awful. So as I've been porting over the behavior over to RSpec, the other tests are using fixtures, and I'm moving that over to use factorybot instead. And at first, I was trying to be minimal with the data that I was bringing over. That failed pretty spectacularly. So I have learned now that I have to go and copy everything that's in the fixtures, and then I move it over to factorybot. And it's painful, but at least then I'm doing that thing that we talked about before where I'm trying to load as little context as possible for each test. But then once I do have a green test, I'm going back through it, and I'm like, okay, we probably don't care about when you were created. We probably don't care when you're updated because every field is set for every single record. So I am going back and then playing a game of if I remove this line, does the test still pass? And if I remove that line, does the test still pass? And so far, that has been painful, but it does have the benefit of then I'm removing some of the setup. So Mystery Guests are very painful. I've also discovered that custom error messages can be tricky because I brought over some tests. And some of these, I'm realizing, are more user error than anything else. Anywho, I added one of the custom error messages that you can add, and I added it over to RSpec. But I had written an incorrect, invalid statement in RSpec where I was looking...I was expecting for a record to exist. But I was using the find by instead of where. So you can call exist on the ActiveRecord relation but not on the actual record that gets returned. But I had the custom error message that was popping up and saying, "Oh, your record wasn't found," and I just kept getting that. So I was then diving through the code to understand again why my record wasn't found. And once I removed that custom error message, I realized that it was actually because of how I'd written the RSpec assertion that was wrong because then RSpec gave me a wonderful message that was like, hey, you're trying to call exist on this record, and you can't do that. Instead, you need to call it on a relation. So I've also learned don't bring over custom error messages until you have a green test, and even then, consider if it's helpful because, frankly, the custom error message wasn't that helpful. It was very similar to what RSpec was going to tell us in general. So there was really no need to add that custom step to it. For the final bit that I've learned or the hurdle that I've been facing is that migrating tests descriptions are hard unless they map over. So RSpec has the context and then a description for it that goes with the test. Test::Unit has methods like method names instead. So it may be something like test redemption codes, and then it runs through the code. Well, as I'm trying to migrate that knowledge over to RSpec, it's not clear to me what we're testing. Okay, we're testing redemption codes. What about them? Should they pass? Should they fail? Should they change? What are they redeeming? There's very little context. So a lot of my tests are copying that method name, so I know which tests I'm focused on, and I'm bringing over. And then in the description, it's like, Steph needs help adding a test description, and then I'm pushing that up and then going to the team for help. So they can help me look through to understand, like, what is it that this test is doing? What's important about this domain? What sort of terminology should I include? And that has been working, but I didn't see that coming as part of this whole migrating stuff over. I really thought this might be a little bit more of a copypasta job. And I have learned some trickery is afoot. And it's been more complicated than I thought it was going to be. CHRIS: Well, at a minimum, I can say thank you for sharing all of your hard-learned lessons throughout this process. This does sound arduous, but hopefully, at the end of it, there will be a lot of value and a cleaned-up test suite and all of those sorts of things. But yeah, it's been an adventure you've been on. So on behalf of the people who you are sharing all of these things with, thank you. STEPH: Well, thank you. Yeah, I'm hoping this is very niche knowledge that there aren't many people in the world that are doing this exact work that this happens to be what this team needs. So yeah, it's been an adventure. I've certainly learned some things from it, and I still have more to go. So not there yet, but I'm also excited for when we can actually then delete this portion of the build process. And then also, I think, get rid of fixtures because I didn't think about that from the beginning either. But now that I'm realizing that's how those tests are working, I suspect we'll be able to delete those. And that'll be really nice because now we also have another single source of truth in factory_bot as to how valid records are being built. Mid-Roll Ad: Flaky tests take the joy out of programming. You push up some code, wait for the tests to run, and the build fails because of a test that has nothing to do with your change. So you click rebuild, and you wait. Again. And you hope you're lucky enough to get a passing build this time. Flaky tests slow everyone down, break your flow and make things downright miserable. In a perfect world, tests would only break if there's a legitimate problem that would impact production. They'd fail immediately and consistently, not intermittently. But the world's not perfect, and flaky tests will happen, and you don't have time to fix them all today. So how do you know where to start? BuildPulse automatically detects and tracks your team's flaky tests. Better still, it pinpoints the ones that are disrupting your team the most. With this list of top offenders, you'll know exactly where to focus your effort for maximum impact on making your builds more stable. In fact, the team at Codecademy was able to identify their flakiest tests with BuildPulse in just a few days. By focusing on those tests first, they reduced their flaky builds by more than 68% in less than a month! And you can do the same because BuildPulse integrates with the tools you're already using. It supports all the major CI systems, including CircleCI, GitHub Actions, Jenkins, and others. And it analyzes test results for all popular test frameworks and programming languages, like RSpec, Jest, Go, pytest, PHPUnit, and more. So stop letting flaky tests slow you down. Start your 14-day free trial of BuildPulse today. To learn more, visit buildpulse.io/ bikeshed. That's buildpulse.io/bikeshed. Pivoting just a bit, there's a listener question that I'm really excited for us to dive into. And this listener question comes from Joël Quenneville. Hey, Joël. All right, so Joël writes in, "As senior-level developers, how do you set goals to ensure that you keep growing? How do you know what are high-value areas for you to improve? How do you stay sharp? Do you just keep adding new languages to your tool belt? Do you pull back and try to dig into more theoretical concepts? Do you feel like you have enough tech skills and pivot to other things like communication or management skills? At the start of a dev career, there's an overwhelming list of things that it feels like you need to know all at once. Eventually, there comes a point where you no longer feel like you're drowning under the list of things that you need to learn. You're at least moderately competent in all the core concepts. So what's next?" This is a big, fun, scary question. I really like this question. Thank you, Joël, for sending it in because I think there's so much here that can be discussed. I can kick us off with a few thoughts. I want to first highlight one of the things that...or one of the things that resonates with me from this question is how Joël describes going through and reaching senior status how it can really feel like working through a backlog of features. So as a developer, I want to understand this particular framework, or as a developer, I want to be able to write clear and fast tests, or as a developer, I want to contribute to an open-source project. But now that that backlog is empty, you're wondering what's next on your roadmap, which is where I think that sort of big, fun scariness comes into play. So the first idea is to take a moment and embrace that success. You have probably worked really hard to get where you're at in your career. And there's nothing wrong with taking a pause and enjoying the view and just being appreciative of the fact that you are able to get your work done quickly or that you feel very confident in the work that you're doing. Growth is often very important to our careers, but I also think it's important to recognize when you've achieved certain growth and then, if you want to, just enjoy that and pause. And you're not constantly pushing yourself to the next level. I think that is a totally reasonable and healthy thing to do. The second thing that comes to mind is that you're on a Choose Your Own Adventure mode now, so you get to...I would encourage folks, once you've reached this stage, to reflect on where you're at and consider what is your dream? What are your aspirations? Maybe they're related to tech; maybe they're not. And consider where is it that you want to go next? And then, what are the concrete steps that will help you achieve those goals? So there's a really great article by Jen Dary, who's a career coach and owner of Plucky Manager Training, that describes this process. And there's a really great blog post that I'll be sure to include a link to in the show notes. But she has a couple of great questions that will then help you identify, like, what are my goals? Some of those questions are, "If I could do anything and money wasn't an object, I'd spend my time doing dot dot dot." And that doesn't necessarily mean sitting on a beach with your toes in the sand all day. I mean, it could, but then that probably just means you need a vacation. So take the vacation. And then, once you start to get bored, where does your mind start to wander? What are the things that you want to do? Where are you interested in spending your time? And then, once you have an idea of how you'd like to spend your time, you can consider what actions you could take next that will point you in that direction. There's also the benefit that by this point, you probably have an idea of the type of things that you like to do and where you like to spend your time. And so you can figure out which areas of expertise you want to invest in. So do you like more greenfield projects? Do you like architecture discussions? Do you like giving talks? Do you like teaching? Or maybe you're interested in management. I think there's also a more concrete approach that you can take that. You can just talk to your managers in your team and say, "Hey, what big, hard problems are you looking to solve? And then, you can get some inspiration from them and see if their problems align with your interests. Maybe it's not even your own team, but you can talk to other companies and see what other problems industries are trying to solve. That might be an area that then spurs some curiosity or some interest. And then, where do you feel underutilized? So with your current day-to-day, are there areas where you feel that you wish you had more responsibilities or more opportunities, but you feel like you don't have access to those opportunities? Maybe that's an area to explore as well. This feels like a wonderful coaching question in terms of you have done it; congratulations. You've reached a really great spot in your career. And so now you're figuring out that big next step. This is going to be highly customized to each person to then figuring out what it is that's going to help you feel fulfilled over the next five years, ten years, however long you want to project out. Those are some of my thoughts. How about you? What do you think? CHRIS: Well, first, those are some great thoughts. I appreciate that I get to follow them now. It's going to be a hard act to follow. But yeah, I think Joël has asked a fantastic question. And coming from Joël, I know how intentional and thoughtful a learner, and sharer, and teacher and all of these things are. So it's all the more sort of framed in that for me knowing Joël personally. I think to start, the kernel of the question is as senior developers, that's the like...or senior level developers is the way Joël phrased it, but it treats it as sort of this discrete moment in time, which I think there's maybe even something to unpack. And I think we've probably talked about this in previous episodes, but like, what does that even mean? And I think part of the story here is going from reactive where it's like, I don't know how anything works. I know a little bit. I can code some. And every day, I'm presented with new problems that I just don't understand. And I'm trying to build up that base of knowledge. Slowly, you know, you start, and it's like 95% of the time you feel like that. And slowly, the dial switches over, and maybe it's only 25% of the time you feel like that. Somewhere along that spectrum is the line of senior developer. I don't actually know where it is, but it's somewhere in there. And so I think it's that space where you can move from reactive learning things as necessitated by the work that's coming at you to I want to proactively choose the things that I want to be learning to try and expand the stuff that I know, and the ways that I can think about the work without being in direct response to a piece of work coming at me. So with that in mind, what do you do with this proactive space? And I think the way Joël frames the question, again, to what I know of Joël, he's such an intentional person. And I wouldn't be surprised if Joël is very purposeful and thinks about this and has approached it as a specific thing that he's doing. I have certainly been in more of “I'll figure it out when I get there.” I'll explore. Or actually, probably the most pointed thing that I did was I joined a consultancy. And that was a very purposeful choice early on in my career because I'm like, I think I know a little bit. I don't think I know a lot. I would like to know a lot. That seems fun. So what do I think is the best way to do that? My guess, and it turned out to be very much true, is if I join a consultancy, I'm going to see a bunch of different projects, different types of technologies, organizations, communication structure, stuff that works, stuff that doesn't work. And to be honest, I actually thought I would try out the consultancy thing for a little while, like a year or two, and then go on to my next adventure. Spoiler alert: I stayed for seven years. It was one of the best periods of my professional life. And I found it to be a much deeper well than I expected it to be. But for anyone that's looking for, like, how can I structure my career in a way that will just automatically provide the sort of novelty and space to grow? I would highly recommend a consultancy like thoughtbot. I wonder if they're hiring. STEPH: Well, yes, we are hiring. That was a perfect plug that I wasn't expecting for that to come. But yes, thoughtbot is totally hiring. We'll include a link in the show notes to all the jobs. [laughs] CHRIS: Sounds fantastic. But very sincerely, that was the best choice that I could have made and was a way to flip the situation around such that I don't have to be thinking about what I want to be learning. The learning will come to me. But even within that, I still tried to be intentional from time to time. And I would say, again, I don't have a holistic theory of how to improve. I just have some stuff that's kind of worked out well. One thing is focusing on fundamentals wherever I can, or a different way to put it is giving myself permission to spend a little bit more time whenever my work brushes up against what I would consider fundamentals. So things that are in that space are like SQL. Every time I'm working on something, I'm like, ah, I could use like a CROSS JOIN here, but I don't know what that is. Maybe I'll spend an extra 30 minutes Googling around and trying to figure out what a CROSS JOIN is. Is that a thing? Is a CROSS JOIN a real thing? I may be making it up. [laughs] A window function, I know that those are real. Maybe I'll learn what a window function is. I think a CROSS JOIN is a real thing. A LEFT OUTER JOIN that's a cool thing. And so, each time I've had that, SQL has been something that expanding my knowledge; I've continually felt like that was a good investment. Or fundamentals of HTTP, that's another one that really has served me well. With Ruby being the primary language that I program in, deeply understanding the language and the fundamentals and the semantics of it that's another place that has been a good investment. But by contrast, I would say I probably haven't gone as deep on the frameworks that I work with. So Rails is maybe a little bit different just because, like many people, I came to Ruby through Rails, and I've learned a lot of Rails. But like in JavaScript, I've worked with many different JavaScript frameworks. And I have been a little more intentional with how much time I invest into furthering my skills in them because I've seen them change and evolve enough times. And if anything, I'm trying to look for ones that are like, what if it's less about the framework and more about JavaScript and web fundamentals underneath? Thus, I've found myself in Svelte land. But I think it's that choice of trying to anchor to fundamentals wherever possible. And then I would say the other thing that's been really beneficial for me is what can I do that's wildly outside the stuff that I already know? And so probably the most pointed example I have of this is learning Elm. So I previously spent most of my career working in Ruby and JavaScript, so primarily object-oriented languages without a strong type system. And then, I was able to go over and experience this whole different paradigm way of working, way of structuring programs, feedback loop. There was so much about it that was really, really interesting. And even though I don't get to work in Elm, frankly, as much as I would want at this point or really at all, it informs everything that I do moving forward. And I think that falls out of the fact that it was so different than what I was doing. So if I were to do that again, probably the next type of language I would learn is Lisp because those are like, well, that's a whole other category of thing that I've heard about. People say some fun stuff about them, but I don't really know. So it's that fundamentals and weird stuff is how I would describe it. And by weird, I mean outside of the core base of knowledge that I have. STEPH: I love that categorization, and I'll stick with it, fundamentals and weird stuff, to stretch and grow and find some other areas. I also really like your framing, the reactive versus proactive. I think that's a really nice way to put it because so much of your career is you are just learning what your company needs you to learn, or you're learning what you need to keep progressing and to feel more competent with the types of features or the work that you're handling. And I think that's why Jen Dary's blog post resonates with me so much because it's probably...up until now, a lot of someone's career, maybe not Joël's particularly, but I know probably for my career, a lot of it has been reactive in terms of what are the things that I need to learn? And so then once you reach that point of like, okay, I feel competent and reasonably good at all the things that I needed to know, where do I want to go next? And rather than focus on necessarily the plans that are laid out in front of me, I can then go wide and think about what are some of the bigger things that I want to tackle? What are the things that are meaningful to me? Because then I can now push forward to this bigger goal versus achieving a particular salary band or title or things like that. But I can focus on something else that I really want to contribute to. And there do seem to be two common paths. So once you reach that level, either you typically go into management, or you become that more like principal and then onward and upward, whatever is after principal. I don't even know what's after that, [laughs] but the titles that come after principal. So there's management, and then I've seen the other very strong contributors, so Aaron Patterson comes to mind. And I feel like those people then typically will migrate to places where they get to contribute to a language or to a framework. And I think it comes down to the idea of impact because both of those provide a greater impact. So if you go into management, you can influence and affect a team of individuals, and you can increase the value created by that team. Then you've likely exceeded the value that you would have created as your own individual contributor. Or, if you contribute to a language or a framework, then your technical decisions impact a larger community. So I think that would be another good thing to reflect on is what type of impact am I looking for? What type of communities do I want to have a positive impact on? And that may spur some inspiration around where you want to go next, the things that you want to focus on. CHRIS: Yeah, I think one of the things we're picking up in that that Joël mentioned in his question is the idea of there is the individual contributor path. But then there's also the management path, which is the typical sort of that's the progression. And I think, for one, naming that the individual contributor path and the idea of going to principal dev and those sorts of outcomes is a fantastic path in and of itself. I think often it's like, well, you know, you go along for a certain amount of time, and then you become a manager. It's like, those are actually distinctly different things. And people have different levels of interest and aptitude in them, and I think recognizing that is critically important. And so, not expecting that management just comes after individual contributor is an important thing. The other thing I'll say is Charity Majors, who we had on the podcast a bit back, has a wonderful blog post about the pendulum swing called The Engineer/Manager Pendulum. And so in it, she talks about folks that have taken an exploration over into manager land and then come back to the individual contributor path or vice versa sort of being able to move between them, treating them as two potentially parallel career tracks but ones that we can move between. And her assertion is that often folks that are particularly strong have spent some time in both camps because then you gain this empathy, this understanding of what's the whole picture? How are we doing all of this? How do we think about communication, et cetera? So, again, to name it, like, I think it's totally fine to stay on one of those tracks to really know which of those tracks speaks to you or to even move between them a little bit and to explore it and to find out what's true. So we'll include a link to that in the show notes. And we'll also include a link to the previous episode a while back when we had Charity on. But yeah, those I think are some critical thoughts as well because those are different areas that we can grow as developers and expand on our impact within the team. And so, we want to make sure we have those options on the table as well. STEPH: Absolutely. I love where teams will support individuals to feel comfortable shifting between experiences like that because it does make you a more well-rounded contributor to that product team, not just as an engineer, but then you will also understand what everybody else is working on and be able to have more meaningful conversations with them about the company goals and then the type of work that's being done. So yeah, I love it. If you're in a place that you can maybe fail a little bit, hopefully not in a too painful way, but you can take a risk and say, "Hey, I want to try something and see if I like it," then I think that's wonderful. And take the risk and see how it goes. And just know that you have an exit strategy should you decide that you don't like that work or that type of work isn't for you. But at least now you know a little bit more about yourself. Overall, I want to respond directly to something that Joël highlighted around how do you know what are high-value areas for you to improve? And I think there are two definitions there because you can either let the people around you and your team define that high value for you, and maybe that really resonates with you, and it's something that you enjoy. And so you can go to your manager and say, "Hey, what are some high-value areas where I can make an impact for the team?" Or it could be very personal. And what are the high-value areas for you? Maybe there's a particular industry that you want to work on. Maybe you want to hit the public speaking circuit. And so you define more intrinsically what are those high-value areas for you? And I think that's a good place to start collecting feedback and start looking at what's high value for you personally and then what's high value to the company and see if there's any overlap there. With that, I think we've covered a good variety of things to explore and then highlighted some of the different ways that you and I have also considered this question. I think it's a fabulous question. Also, I think it's one, even if you're not at that senior level, to ask this question. Like, go ahead and start asking it early and often and revisit your answers and see how they change. I think that would be a really powerful habit to establish early in your career and then could help guide you along, and then you can reflect on some of your earlier choices. So, Joël, thank you so much for that question. STEPH: On that note, shall we wrap up? CHRIS: Let's wrap up. The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

The Bike Shed
339: What About Pictures?

The Bike Shed

Play Episode Listen Later May 24, 2022 45:03


Steph has a baby update and thoughts on movies, plus a question for Chris related to migrating Test Unit tests to RSpec. Chris watched a video from Google I/O where Chrome devs talked about a new feature called Page Transitions. He's also been working with a tool called Customer.io, an omnichannel communication whiz-bang adventure! Page transitions Overview (https://youtu.be/JCJUPJ_zDQ4) Using yield_self for composable ActiveRecord relations (https://thoughtbot.com/blog/using-yieldself-for-composable-activerecord-relations) A Case for Query Objects in Rails (https://thoughtbot.com/blog/a-case-for-query-objects-in-rails) Customer.io (https://customer.io/) Turning the database inside-out with Apache Samza | Confluent (https://www.confluent.io/blog/turning-the-database-inside-out-with-apache-samza/) Datomic (https://www.datomic.com/) About CRDTs • Conflict-free Replicated Data Types (https://crdt.tech/) Apache Kafka (https://kafka.apache.org/) Resilient Management | A book for new managers in tech (https://resilient-management.com/) Mixpanel: Product Analytics for Mobile, Web, & More (https://mixpanel.com/) Become a Sponsor (https://thoughtbot.com/sponsorship) of The Bike Shed! Transcript: CHRIS: Golden roads are golden. Okay, everybody's got golden roads. You have golden roads, yes? That is what we're -- STEPH: Oh, I have golden roads, yes. [laughter] CHRIS: You might should inform that you've got golden roads, yeah. STEPH: Yeah, I don't know if I say might should as much but might could. I have been called out for that one a lot; I might could do that. CHRIS: [laughs] STEPH: That one just feels so natural to me than normal. Anytime someone calls it out, I'm like, yeah, what about it? [laughter] CHRIS: Do you want to fight? STEPH: Yeah, are we going to fight? CHRIS: I might could fight you. STEPH: I might could. I might should. [laughter] CHRIS: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Chris Toomey. STEPH: And I'm Steph Viccari. CHRIS: And together, we're here to share a bit of what we've learned along the way. So, Steph, what's new in your world? STEPH: Hey, Chris. I have a couple of fun updates. I have a baby Viccari update, so little baby weighs about two pounds now, two pounds. I'm 25 weeks along. So not that I actually know the exact weight, I'm using all those apps that estimate based on how far along you are, so around two pounds, which is novel. Oh, and then the other thing I'm excited to tell you about...I'm not sure how I should feel that I just got more excited about this other thing. I'm very excited about baby Viccari. But the other thing is there's a new Jurassic Park movie coming out, and I'm very excited. I think it's June 10th is when it comes out. And given how much we have sung that theme song to each other and make references to what a clever girl, I needed to share that with you. Maybe you already know, maybe you're already in the loop, but if you don't, it's coming. CHRIS: Yeah, the internet likes to yell things like that. Have you watched all of the most recent ones? There are like two, and I think this will be the third in the revisiting or whatever, the Jurassic World version or something like that. But have you watched the others? STEPH: I haven't seen all of them. So I've, of course, seen the first one. I saw the one that Chris Pratt was in, and now he's in the latest one. But I think I've missed...maybe there's like two in the middle there. I have not watched those. CHRIS: There are three in the original trilogy, and then there are three now in the new trilogy, which now it's ending, and they got everybody. STEPH: Oh, I'm behind. CHRIS: They got people from the first one, and they got the people from the second trilogy. They just got everybody, and that's exciting. You know, it's that thing where they tap into nostalgia, and they take advantage of us via it. But I'm fine. I'm here for it. STEPH: I'm here for it, especially for Jurassic Park. But then there's also a new Top Gun movie coming out, which, I'll be honest, I'm totally going to watch. But I really didn't remember the first one. I don't know that I've really ever watched the first Top Gun. So Tim, my partner, and I watched that recently, and it's such a bad movie. I'm going to say it; [laughs] it's a bad movie. CHRIS: I mean, I don't want to disagree, but the volleyball scene, come on, come on, the volleyball scene. [laughter] STEPH: I mean, I totally had a good time watching the movie. But the one part that I finally kept complaining about is because every time they showed the lead female character, I can't think of her character name or the actress's name, but they kept playing that song, Take My Breath Away. And I was like, can we just get past the song? [laughs] Because if you go back and watch that movie, I swear they play it like six different times. It was a lot. It was too much. So I moved it into bad movie category but bad movie totally worth watching, whatever category that is. CHRIS: Now I kind of want to revisit it. I feel like the drinking game writes itself. But at a minimum, anytime Take My Breath Away plays, yeah. Well, all right, good to know. [laughs] STEPH: Well, if you do that, let me know how many shots or beers you drink because I think it will be a fair amount. I think it will be more than five. CHRIS: Yeah, it involves a delicate calibration to get that right. I don't think it's the sort of thing you just freehand. It writes itself but also, you want someone who's tried it before you so that you're not like, oh no, it's every time they show a jet. That was too many. You can't drink that much while watching this movie. STEPH: Yeah, that would be death by Top Gun. CHRIS: But not the normal way, the different, indirect death by Top Gun. STEPH: I don't know what the normal way is. [laughs] CHRIS: Like getting shot down by a Top Gun pilot. [laughter] STEPH: Yeah, that makes sense. [laughs] CHRIS: You know, the dogfighting in the plane. STEPH: The actual, yeah, going to war away. Just sitting on your couch and you drink too much poison away, yeah, that one. All right, that got weird. Moving on, [laughs] there's a new Jurassic Park movie. We're going to land on that note. And in the more technical world, I've got a couple of things on my mind. One of them is I have a question for you. I'm very excited to run this by you because I could use a friend in helping me decide what to do. So I am still on that journey where I am migrating Test::Unit test over to RSpec. And as I'm going through, it's going pretty well, but it's a little complicated because some of the Test::Unit tests have different setup than, say, the RSpec do. They might run different scripts beforehand where they're loading data. That's perhaps a different topic, but that's happening. And so that has changed a few things. But then overall, I've just been really just porting everything over, like, hey, if it exists in the Test::Unit, let's just bring it to RSpec, and then I'm going to change these asserts to expects and really not make any changes from there. But as I'm doing that, I'm seeing areas that I want to improve and things that I want to clear up, even if it's just extracting a variable name. Or, as I'm moving some of these over in Test::Unit, it's not clear to me exactly what the test is about. Like, it looks more like a method name in the way that the test is being described, but the actual behavior isn't clear to me as if I were writing this in RSpec, I think it would have more of a clear description. Maybe that's not specific to the actual testing framework. That might just be how these tests are set up. But I'm at that point where I'm questioning should I keep going in terms of where I am just copying everything over from Test::Unit and then moving it over to RSpec? Because ultimately, that is the goal, to migrate over. Or should I also include some time to then go back and clean up and try to add some clarity, maybe extract some variable names, see if I can reduce some lets, maybe even reduce some of the test helpers that I'm bringing over? How much cleanup should be involved, zero, lots? I don't know. I don't know what that...[laughs] I'm sure there's a middle ground in there somewhere. But I'm having trouble discerning for myself what's the right amount because this feels like one of those areas where if I don't do any cleanup, I'm not coming back to it, like, that's just the truth. So it's either now, or I have no idea when and maybe never. CHRIS: I'll be honest, the first thing that came to mind in this most recent time that you mentioned this is, did we consider just deleting these tests entirely? Is that on...like, there are very few of them, right? Like, are they even providing enough value? So that was question one, which let me pause to see what your thoughts there were. [chuckles] STEPH: I don't know if we specifically talked about that on the mic, but yes, that has been considered. And the team that owns those tests has said, "No, please don't delete them. We do get value from them." So we can port them over to RSpec, but we don't have time to port them over to RSpec. So we just need to keep letting them go on. But yet, not porting them conflicts with my goal of then trying to speed up CI. And so it'd be nice to collapse these Test::Unit tests over to RSpec because then that would bring our CI build down by several meaningful minutes. And also, it would reduce some of the complexity in the CI setup. CHRIS: Gotcha. Okay, so now, having set that aside, I always ask the first question of like, can you just put Derek Prior's phone number on the webpage and call it an app? Is that the MVP of this app? No? Okay, all right, we have to build more. But yeah, I think to answer it and in a general way of trying to answer a broader set of questions here... I think this falls into a category of like if you find yourself having to move around some code, if that code is just comfortably running and the main thing you need to do is just to get it ported over to RSpec, I would probably do as little other work as possible. With the one consideration that if you find yourself needing to deeply load up the context of these tests like actually understand them in order to do the porting, then I would probably take advantage of that context because it's hard to get your head into a given piece of code, test or otherwise. And so if you're in there and you're like, well, now that I'm here, I can definitely see that we could rearrange some stuff and just definitively make it better, if you get to that place, I would consider it. But if this ends up being mostly a pretty rote transformation like you said, asserts become expects, and lets get switched around, you know, that sort of stuff, if it's a very mechanical process of getting done, I would probably say very minimal. But again, if there is that, like, you know what? I had to understand the test in order to port them anyway, so while I'm here, let me take advantage of that, that's probably the thing that I would consider. But if not that, then I would say even though it's messy and whatnot and your inclination would be to clean it, I would say leave it roughly as is. That's my guess or how I would approach it. STEPH: Yeah, I love that. I love how you pointed out, like, did you build up the context? Because you're right, in a lot of these test cases, I'm not, or I'm trying really hard to not build up context. I'm trying very hard to just move them over and, if I have to, mainly to find test descriptions. That's the main area I'm struggling to...how can I more explicitly state what this test does so the next person reading this will have more comprehension than I do? But otherwise, I'm trying hard to not have any real context around it. And that's such a good point because that's often...when someone else is in the middle of something, and they're deciding whether to include that cleanup or refactor or improvement, one of my suggestions is like, hey, we've got the context now. Let's go with it. But if you've built up very little context, then that's not a really good catalyst or reason to then dig in deeper and apply that cleanup. That's super helpful. Thank you. That will help reinforce what I'm going to do, which is exactly let's migrate RSpec and not worry about cleanup, which feels terrible; I'm just going to say that into the world. But it also feels like the right thing to do. CHRIS: Well, I'm happy to have helped. And I share the like, and it feels terrible. I want to do the right thing, but sometimes you got to pick a battle sort of thing. STEPH: Cool. Well, that's a huge help to me. What's going on in your world? CHRIS: What's going on in my world? I watched a great video the other day from the Google I/O. I think it's an event; I'm not actually sure, conference or something like that. But it was some Google Chrome developers talking about a new feature that's coming to the platform called Page Transitions. And I've kept an eye on this for a while, but it seems like it's more real. Like, I think they put out an RFC or an initial sort of set of ideas a while back. And the web community was like, "Oh, that's not going to work out so well." So they went back to the drawing board, revisited. I've actually implemented in Chrome Canary a version of the API. And then, in the video that I watched, which we'll include a show notes link to, they demoed the functionality of the Page Transitions API and showed what you can do. And it's super cool. It allows for the sort of animations that you see in a lot of native mobile apps where you're looking at a ListView, you click on one of the items, and it grows to fill the whole screen. And now you're on the detail screen for that item that you were looking at. But there was this very continuous animated transition that allows you to keep context in your head and all of those sorts of nice things. And this just really helps to bridge that gap between, like, the web often lags behind the native mobile platforms in terms of the experiences that we can build. So it was really interesting to see what they've been able to pull off. The demo is a pretty short video, but it shows a couple of different variations of what you can build with it. And I was like, yeah, these look like cool native app transitions, really nifty. One thing that's very interesting is the actual implementation of this. So it's like you have one version of the page, and then you transition to a new version of the page, and in doing so, you want to animate between them. And the way that they do it is they have the first version of the page. They take a screenshot of it like the browser engine takes a screenshot of it. And then they put that picture on top of the actual browser page. Then they do the same thing with the next version of the page that they're going to transition to. And then they crossfade, like, change the opacity and size and whatnot between the two different images, and then you're there. And in the back of my mind, I'm like, I'm sorry, what now? You did which? I'm like, is this the genius solution that actually makes this work and is performant? And I wonder if there are trade-offs. Like, do you lose interactivity between those because you've got some images that are just on the screen? And what is that like? But as they were going through it, I was just like, wait, I'm sorry, you did what? This is either the best idea I've ever heard, or I'm not so sure about this. STEPH: That's fascinating. You had me with the first part in terms of they take a screenshot of the page that you're leaving. I'm like, yeah, that's a great idea. And then talking about taking a picture of the other page because then you have to load it but not show it to the user that it's loaded. And then take a picture of it, and then show them the picture of the loaded page. But then actually, like you said, then crossfade and then bring in the real functionality. I am...what am I? [laughter] CHRIS: What am I actually? STEPH: [laughs] What am I? I'm shocked. I'm surprised that that is so performant. Because yeah, I also wouldn't have thought of that, or I would have immediately have thought like, there's no way that's going to be performant enough. But that's fascinating. CHRIS: For me, performance seems more manageable, but it's the like, what are you trading off for that? Because that sounds like a hack. That sounds like the sort of thing I would recommend if we need to get an MVP out next week. And I'm like, what if we just tried this? Listen, it's got some trade-offs. So I'm really interested to see are those trade-offs present? Because it's the browser engine. It's, you know, the low-level platform that's actually managing this. And there are some nice hooks that allow you to control it. And at a CSS level, you can manage it and use keyframe animations to control the transition more directly. There's a JavaScript API to instrument the sequencing of things. And so it's giving you the right primitives and the right hooks. And the fact that the implementation happens to use pictures or screenshots, to use a slightly different word, it's like, okey dokey, that's what we're doing. Sounds fun. So I'm super interested because the functionality is deeply, deeply interesting to me. Svelte actually has a version of this, the crossfade utility, but you have to still really think about how do you sequence between the two pages and how do you do the connective tissue there? And then Svelte will manage it for you if you do all the right stuff. But the wiring up is somewhat complicated. So having this in the browser engine is really interesting to me. But yeah, pictures. STEPH: This is one of those ideas where I can't decide if this was someone who is very new to the team and new to the idea and was like, "Have we considered screenshots? Have we considered pictures?" Or if this is like the uber senior person on the team that was like, "Yeah, this will totally work with screenshots." I can't decide where in that range this idea falls, which I think makes me love it even more. Because it's very straightforward of like, hey, what if we just tried this? And it's working, so cool, cool, cool. CHRIS: There's a fantastic meme that's been making the rounds where it's a bell curve, and it's like, early in your career, middle of your career, late in your career. And so early in your career, you're like, everything in one file, all lines of code that's just where they go. And then in the middle of your career, you're like, no, no, no, we need different concerns, and files, and organizational structures. And then end of your career...and this was coming up in reference to the TypeScript team seems to have just thrown everything into one file. And it's the thing that they've migrated to over time. And so they have this many, many line file that is basically the TypeScript engine all in one file. And so it was a joke of like, they definitely know what they're doing with programming. They're not just starting last week sort of thing. And so it's this funny arc that certain things can go through. So I think that's an excellent summary there [laughs] of like, I think it was folks who have thought about this really hard. But I kind of hope it was someone who was just like, "I'm new here. But have we thought about pictures? What about pictures?" I also am a little worried that I just deeply misunderstood [laughs] the representation but glossed over it in the video, and I'm like, that sounds interesting. So hopefully, I'm not just wildly off base here. [laughs] But nonetheless, the functionality looks very interesting. STEPH: That would be a hilarious tweet. You know, I've been waiting for that moment where I've said something that I understood into the mic and someone on Twitter just being like, well, good try, but... [laughs] CHRIS: We had a couple of minutes where we tried to figure out what the opposite of ranting was, and we came up with pranting and made up a word instead of going with praising or raving. No, that's what it is, raving. [laughs] STEPH: No, raving. I will never forget now, raving. [laughs] CHRIS: So, I mean, we've done this before. STEPH: That's true. Although they were nice, I don't think they tweeted. I think they sent in an email. They were like, "Hey, friends." [laughter] CHRIS: Actually, we got a handful of emails on that. [laughter] STEPH: Did you know the English language? CHRIS: Thank you, kind Bikeshed audience, for not shaming us in public. I mean, feel free if you feel like it. [laughs] But one other thing that came up in this video, though, is the speaker was describing single-page apps are very common, and you want to have animated transitions and this and that. And I was like, single-page app, okay, fine. I don't like the terminology but whatever. I would like us to call it the client-side app or client-side routing or something else. But the fact that it's a single page is just a technical consideration that no user would call it that. Users are like; I go to the web app. I like that it has URLs. Those seem different to me. Anyway, this is my hill. I'm going to die on it. But then the speaker in the video, in contrast to single-page app referenced multi-page app, and I was like, oh, come on, come on. I get it. Like, yes, there are just balls of JavaScript that you can download on the internet and have a dynamic graphics editor. But I think almost all good things on the web should have URLs, and that's what I would call the multiple pages. But again, that's just me griping about some stuff. And to name it, I don't think I'm just griping for griping sake. Like, again, I like to think about things from the user perspective, and the URL being so important. And having worked with plenty of apps that are implemented in JavaScript and don't take the URL or the idea that we can have different routable resources seriously and everything is just one URL, that's a failure mode in my mind. We missed an opportunity here. So I think I'm saying a useful thing here and not just complaining on the internet. But with that, I will stop complaining on the internet and send it back over to you. What else is new in your world, Steph? STEPH: I do remember the first time that you griped about it, and you were griping about URLs. And there was a part of me that was like, what is he talking about? [laughter] And then over time, I was like, oh, I get it now as I started actually working more in that world. But it took me a little bit to really appreciate that gripe and where you're coming from. And I agree; I think you're coming from a reasonable place, not that I'm biased at all as your co-host, but you know. CHRIS: I really like the honest summary that you're giving of, like, honestly, the first time you said this, I let you go for a while, but I did not know what you were talking about. [laughs] And I was like, okay, good data point. I'm going to store that one away and think about it a bunch. But that's fine. I'm glad you're now hanging out with me still. [laughter] STEPH: Don't do that. Don't think about it a bunch. [laughs] Let's see, oh, something else that's going on in my world. I had a really fun pairing session with another thoughtboter where we were digging into query objects and essentially extracting some logic out of an ActiveRecord model and then giving that behavior its own space and elevated namespace in a query object. And one of the questions or one of the things that came up that we needed to incorporate was optional filters. So say if you are searching for a pizza place that's nearby and you provide a city, but you don't provide what's the optional zip code, then we want to make sure that we don't apply the zip code in the where clause because then you would return all the pizza places that have a nil zip code, and that's just not what you want. So we need to respect the fact that not all the filters need to be applied. And there are a couple of ways to go about it. And it was a fun journey to see the different ways that we could structure it. So one of the really good starting points is captured in a blog post by Derek Prior, which we'll include a link to in the show notes, and it's using yield_self for composable ActiveRecord relations. But essentially, it starts out with an example where it shows that you're assigning a value to then the result of an if statement. So it's like, hey, if the zip code is present, then let's filter by zip code; if not, then just give us back the original relation. And then you can just keep building on it from there. And then there's a really nice implementation that Derek built on that then uses yield_self to pass the relation through, which then provides a really nice readability for as you are then stepping through each filter and which one should and shouldn't be applied. And now there's another blog post, and this one's written by Thiago Silva, A Case for Query Objects in Rails. And this one highlighted an approach that I haven't used before. And I initially had some mixed feelings about it. But this approach uses the extending method, which is a method that's on ActiveRecord query methods. And it's used to extend the scope with additional methods. You can either do this by providing the name of a module or by providing a block. It's only going to apply to that instance or to that specific scope when you're using it. So it's not going to be like you're running an include or something like that where all instances are going to now have access to these methods. So by using that method, extending, then you can create a module that says, "Hey, I want to create this by zip code filter that will then check if we have a zip code, let's apply it, if not, return the relation. And it also creates a really pretty chaining experience of like, here's my original class name. Let's extend with these specific scopes, and then we can say by zip code, by pizza topping, whatever else it is that we're looking to filter by. And I was initially...I saw the extending, and it made me nervous because I was like, oh, what all does this apply to? And is it going to impact anything outside of this class? But the more I've looked at it, the more I really like it. So I think you've seen this blog post too. And I'm curious, what are your thoughts about this? CHRIS: I did see this blog post come through. I follow that thoughtbot blog real close because it turns out some of the best writing on the internet is on there. But I saw this...also, as an aside, I like that we've got two Derek Prior references in one episode. Let's see if we can go for three before the end. But one thing that did stand out to me in it is I have historically avoided scopes using scope like ActiveRecord macro thing. It's a class method, but like, it's magic. It does magic. And a while ago, class methods and scopes became roughly equivalent, not exactly equivalent, but close enough. And for me, I want to use methods because I know stuff about methods. I know about default arguments. And I know about all of these different subtleties because they're just methods at the end of the day, whereas scopes are special; they have certain behavior. And I've never really known of the behavior beyond the fact that they get implemented in a different way. And so I was never really sold on them. And they're different enough from methods, and I know methods well. So I'm like, let's use the normal stuff where we can. The one thing that's really interesting, though, is the returning nil that was mentioned in this blog post. If you return nil in a scope, it will handle that for you. Whereas all of my query objects have a like, well, if this thing applies, then scope dot or relation dot where blah, blah, blah, else return relation unchanged. And the fact that that natively exists within scope is interesting enough to make me reconsider my stance on scopes versus class methods. I think I'm still doing class method. But it is an interesting consideration that I was unaware of before. STEPH: Yeah, it's an interesting point. I hadn't really considered as much whether I'm defining a class-level method versus a scope in this particular case. And I also didn't realize that scopes handle that nil case for you. That was one of the other things that I learned by reading through this blog post. I was like, oh, that is a nicety. Like, that is something that I get for free. So I agree. I think this is one of those things that I like enough that I'd really like to try it out more and then see how it goes and start to incorporate it into my process. Because this feels like one of those common areas of where I get to it, and I'm like, how do I do this again? And yield_self was just complicated enough in terms of then using the fancy method method to then be able to call the method that I want that I was like, I don't remember how to do this. I had to look it up each time. But including this module with extending and then being able to use scopes that way feels like something that would be intuitive for me that then I could just pick up and run with each time. CHRIS: If it helps, you can use then instead of yield_self because we did upgrade our Ruby a while back to have that change. But I don't think that actually solves the thing that you're describing. I'd have liked the ampersand method and then simple method name magic incantation that is part of the thing that Derek wrote up. I do use it when I write query objects, but I have to think about it or look it up each time and be like, how do I do that? All right, that's how I do that. STEPH: Yeah, that's one of the things that I really appreciate is how often folks will go back and update blog posts, or they will add an addition to them to say, "Hey, there's something new that came out that then is still relevant to this topic." So then you can read through it and see the latest and the greatest. It's a really nice touch to a number of our blog posts. But yeah, that's what was on my mind regarding query objects. What else is going on in your world? CHRIS: I have this growing feeling that I don't quite know what to do with. I think I've talked about it across some of our conversations in the world of observability. But broadly, I'm starting to like...I feel like my brain has shifted, and I now see the world slightly differently, and I can't go back. But I also don't know how to stick the landing and complete this transition in my brain. So it's basically everything's an event stream; this feels true. That's life. The arrow of time goes in one direction as far as I understand it. And I'm now starting to see it manifest in the code that we're writing. Like, we have code to log things, and we have places where we want to log more intentionally. Then occasionally, we send stuff off to Sentry. And Sentry tells us when there are errors, that's great. But in a lot of places, we have both. Like, we will warn about something happening, and we'll send that to the logs because we want to have that in the logs, which is basically the whole history of what's happened. But we also have it in Sentry, but Sentry's version is just this expanded version that has a bunch more data about the user, and things, and the browser that they were in. But they're two variations on the same event. And then similarly, analytics is this, like, third leg of well, this thing happened, and we want to know about it in the context. And what's been really interesting is we're working with a tool called Customer.io, which is an omnichannel communication whiz-bang adventure. For us, it does email, SMS, and push notifications. And it's integrated into our segment pipeline, so events flow in, events and users essentially. So we have those two different primitives within it. And then within it, we can say like, when a user does X, then send them an email with this copy. As an aside, Customer.io is a fantastic platform. I'm super-duper impressed. We went through a search for a tool like it, and we ended up on a lot of sales demos with folks that were like, hey, so yeah, starting point is $25,000 per year. And, you know, we can talk about it, but it's only going to go up from there when we talk about it, just to be clear. And it's a year minimum contract, and you're going to love it. And we're like, you do have impressive platforms, but okay, that's a bunch. And then, we found Customer.io, and it's month-by-month pricing. And it had a surprisingly complete feature set. So overall, I've been super impressed with Customer.io and everything that they've afforded. But now that I'm seeing it, I kind of want to move everything into that world where like, Customer.io allows non-engineer team members to interact with that event stream and then make things happen. And that's what we're doing all the time. But I'm at that point where I think I see the thing that I want, but I have no idea how to get there. And it might not even be tractable either. There's the wonderful Turning the Database Inside Out talk, which describes how everything is an event stream. And what if we actually were to structure things that way and do materialized views on top of it? And the actual UI that you're looking at is a materialized view on top of the database, which is a materialized view on top of that event stream. So I'm mostly in this, like, I want to figure this out. I want to start to unify all this stuff. And analytics pipes to one tool that gets a version of this event stream, and our logs are just another, and our error system is another variation on it. But they're all sort of sampling from that one event stream. But I have no idea how to do that. And then when you have a database, then you're like, well, that's also just a static representation of a point in time, which is the opposite of an event stream. So what do you do there? So there are folks out there that are doing good thinking on this. So I'm going to keep my ear to the ground and try and see what's everybody thinking on this front? But I can't shake the feeling that there's something here that I'm missing that I want to stitch together. STEPH: I'm intrigued on how to take this further because everything you're saying resonates in terms of having these event streams that you're working with. But yet, I can't mentally replace that with the existing model that I have in my mind of where there are still certain ideas of records or things that exist in the world. And I want to encapsulate the data and store that in the database. And maybe I look it up based on when it happens; maybe I don't. Maybe I'm looking it up by something completely different. So yeah, I'm also intrigued by your thoughts, but I'm also not sure where to take it. Who are some of the folks that are doing some of the thinking in this area that you're interested in, or where might you look next? CHRIS: There's the Kafka world of we have an event log, and then we're processing on top of that, and we're building stream processing engines as the core. They seem to be closest to the Turning the Database Inside Out talk that I was thinking or that I mentioned earlier. There's also the idea of CRDTs, which are Conflict-free Replicated Data Types, which are really interesting. I see them used particularly in real-time application. So it's this other tool, but they are basically event logs. And then you can communicate them well and have two different people working on something collaboratively. And these event logs then have a natural way to come together and produce a common version of the document on either end. That's at least my loose understanding of it, but it seems like a variation on this theme. So I've been looking at that a little bit. But again, I can't see how to map that to like, but I know how to make a Rails app with a Postgres database. And I think I'm reasonably capable at it, or at least I've been able to produce things that are useful to humans using it. And so it feels like there is this pretty large gap. Because what makes sense in my head is if you follow this all the way, it fundamentally re-architects everything. And so that's A, scary, and B; I have no idea how to get there, but I am intrigued. Like, I feel like there's something there. There's also Datomic is the other thing that comes to mind, which is a database engine in the Clojure world that stores the versions of things over time; that idea of the user is active. It's like, well, yeah, but when were they not? That's an event. That transition is an event that Postgres does not maintain at this point. And so, all I know is that the user is active. Maybe I store a timestamp because I'm thinking proactively about this. But Datomic is like no, no, fundamentally, as a primitive in this database; that's how we organize and think about stuff. And I know I've talked about Datomic on here before. So I've circled around these ideas before. And I'm pretty sure I'm just going to spend a couple of minutes circling and then stop because I have no idea how to connect the dots. [laughs] But I want to figure this out. STEPH: I have not worked with Kafka. But one of the main benefits I understand with Kafka is that by storing everything as a stream, you're never going to lose like a message. So if you are sending a message to another system and then that message gets lost in transit, you don't actually know if it got acknowledged or what happened with it, and replaying is really hard. Where do you pick up again? While using something like Kafka, you know exactly what you sent last, and then you're not going to have that uncertainty as to what messages went through and which ones didn't. And then the ability to replay is so important. I'm curious, as you continue to explore this, do you have a particular pain point in mind that you'd like to see improve? Or is it more just like, this seems like a really cool, novel idea; how can I incorporate more of this into my world? CHRIS: I think it's the latter. But I think the thing that I keep feeling is we keep going back and re-instrumenting versions of this. We're adding more logging or more analytics events over the wire or other things. But then, as I send these analytics events over the wire, we have Mixpanel downstream as an analytics visualization and workflow tool or Customer.io. At this point, those applications, I think, have a richer understanding of our users than our core Rails app. And something about that feels wrong to me. We're also streaming everything that goes through segment to S3 because I had a realization of this a while back. I'm like, that event stream is very interesting. I don't want to lose it. I'm going to put it somewhere that I get to keep it. So even if we move off of either Mixpanel or Customer.io or any of those other platforms, we still have our data. That's our data, and we're going to hold on to it. But interestingly, Customer.io, when it sends a message, will push an event back into segments. So it's like doubly connected to segment, which is managing this sort of event bus of data. And so Mixpanel then gets an even richer set there, and the Rails app is like, I'm cool. I'm still hanging out, and I'm doing stuff; it's fine. But the fact that the Rails app is fundamentally less aware of the things that have happened is really interesting to me. And I am not running into issues with it, but I do feel odd about it. STEPH: That touched on a theme that is interesting to me, the idea that I hadn't really considered it in those terms. But yeah, our application provides the tool in which people can interact with. But then we outsource the behavior analysis of our users and understanding what that flow is and what they're going through. I hadn't really thought about those concrete terms and where someone else owns the behavior of our users, but yet we own all the interaction points. And then we really need both to then make decisions about features and things that we're building next. But that also feels like building a whole new product, that behavior analysis portion of it, so it's interesting. My consulting brain is going wild at the moment between like, yeah, it would be great to own that. But that the other time if there's this other service that has already built that product and they're doing it super well, then let's keep letting them manage that portion of our business until we really need to bring it in-house. Because then we need to incorporate it more into our application itself so then we can surface things to the user. That's the part where then I get really interested, or that's the pain point that I could see is if we wanted more of that behavior analysis, that then we want to surface that in the app, then always having to go to a third-party would start to feel tedious or could feel more brittle. CHRIS: Yeah, I'm definitely 100% on not rebuilding Mixpanel in our app and being okay with the fact that we're sending that. Again, the thing that I did to make myself feel better about this is stream the data to S3 so that I have a version of it. And if we want to rebuild the data warehouse down the road to build some sort of machine learning data pipeline thing, we've got some raw data to work with. But I'm noticing lots of places where we're transforming a side effect, a behavior that we have in the system to dispatching an event. And so right now, we have a bunch of stuff that we pipe over to Slack to inform our admin team, hey, this thing happened. You should probably intervene. But I'm looking at that, and we're doing it directly because we can control the message in Slack a little bit better. But I had this thought in the back of my mind; it's like, could we just send that as an event, and then some downstream tool can configure messages and alerts into Slack? Because then the admin team could actually instrument this themselves. And they could be like; we are no longer interested in this event. Users seem fine on that front. But we do care about this new event. And all we need to do as the engineering team is properly instrument all of that event stream tapping. Every event just needs to get piped over. And then lots of powerful tools downstream from that that can allow different consumers of that data to do things, and broadly, that dispatch events, consume them on the other side, do fun stuff. That's the story. That's the dream. But I don't know; I can't connect all the dots. It's probably going to take me a couple of weeks to connect all these dots, or maybe years, or maybe my entire career, something like that. But, I don't know, I'm going to keep trying. STEPH: This feels like a fun startup narrative, though, where you start by building the thing that people can interact with. As more people start to interact with it, how do we start giving more of our team the ability to then manage the product that then all of these users are interacting with? And then that's the part that you start optimizing for. So there are always different interesting bits when you talk about the different stages of Sagewell, and like, what's the thing you're optimizing for? And I'm sure it's still heavily users. But now there's also this addition of we are also optimizing for our team to now manage the product. CHRIS: Yes, you're 100%. You're spot on there. We have definitely joked internally about spinning out a small company to build this analytics alerting tool [laughs] but obviously not going to do that because that's a distraction. And it is interesting, like, we want to build for the users the best thing that we can and where the admin team fits within that. To me, they're very much customers of engineering. Our job is to build the thing for the users but also, to be honest, we have to build a thing for the admins to support the users and exactly where that falls. Like, you and I have talked a handful of times about maybe the admin isn't as polished in design as other things. But it's definitely tested because that's a critical part of how this application works. Maybe not directly for a user but one step removed for a user, so it matters. Absolutely we're writing tests to cover that behavior. And so yeah, those trade-offs are always interesting to me and exploring that space. But 100%: our admin team are core customers of the work that we're doing in engineering. And we try and stay very close and very friendly with them. STEPH: Yeah, I really appreciate how you're framing that. And I very much agree and believe with you that our admin users are incredibly important. CHRIS: Well, thank you. Yeah, we're trying over here. But yeah, I think I can wrap up that segment of me rambling about ideas that are half-formed in my mind but hopefully are directionally important. Anyway, what else is up with you? STEPH: So, not that long ago, I asked you a question around how the heck to manage themes that I have going on. So we've talked about lots of fun productivity things around managing to-dos, and emails, and all that stuff. And my latest one is thinking about, like, I have a theme that I want to focus on, maybe it's this week, maybe it's for a couple of months. And how do I capture that and surface it to myself and see that I'm making progress on that? And I don't have an answer to that. But I do have a theme that I wanted to share. And the one that I'm currently focused on is building up management skills and team lead skills. That is something that I'm focused on at the moment and partially because I was inspired to read the book Resilient Management written by Lara Hogan. And so I think that is what has really set the idea. But as I picked up the book, I was like, this is a really great book, and I'd really like to share some of this. And then so that grew into like, well, let's just go ahead and make this a theme where I'm learning this, and I'm sharing this with everyone else. So along that note, I figured I would share that here. So we use Basecamp at thoughtbot. And so, I've been sharing some Basecamp posts around what I'm learning in each chapter. But to bring some of that knowledge here as well, some of the cool stuff that I have learned so far...and this is just still very early on in the book. There are a couple of different topics that Laura covers in the first chapter, and one of them is humans' core needs at work. And then there's also the concept of meeting your team, some really good questions that you can ask during your first one-on-one to get to know the person that then you're going to be managing. The part that really resonated with me and something that I would like to then coach myself to try is helping the team get to know you. So as a manager, not only are you going out of your way to really get to know that person, but how are you then helping them get to know you as well? Because then that's really going to help set that relationship in regards of they know what kind of things that you're optimizing for. Maybe you're optimizing for a deadline, or for business goals, or maybe it's for transparency, or maybe it would be helpful to communicate to someone that you're managing to say, "Hey, I'm trying some new management techniques. Let me know how this goes." [chuckles] So there's a healthier relationship of not only are you learning them, but they're also learning you. So some of the questions that Laura includes as examples as something that you can share with your team is what do you optimize for in your role? So is it that you're optimizing for specific financial goals or building up teammates? Or maybe it's collaboration, so you're really looking for opportunities for people to pair together. What do you want your teammates to lean on you for? I really liked that question. Like, what are some of the areas that bring you joy or something that you feel really skilled in that then you want people to come to you for? Because that's something that before I was a manager...but it's just as you are growing as a developer, that's such a great question of like, what do you want to be known for? What do you want to be that thing that when people think of, they're like, oh, you should go see Chris about this, or you should go see Steph about this? And two other good questions include what are your work styles and preferences? And what management skills are you currently working on learning or improving? So I really like this concept of how can I share more of myself? And the great thing about this book that I'm learning too is while it is geared towards people that are managers, I think it's so wonderful for people who are non-managers or aspiring managers to read this as well because then it can help you manage whoever's managing you. So then that way, you can have some upward management. So we had recent conversations around when you are new to a team and getting used to a manager, or maybe if you're a junior, you have to take a lot of self-advocacy into your role to make sure things are going well. And I think this book does a really good job for people that are looking to not only manage others but also manage themselves and manage upward. So that's some of the journeys from the first chapter. I'll keep you posted on the other chapters as I'm learning more. And yeah, if anybody hasn't read this book or if you're interested, I highly recommend it. I'll make sure to include a link in the show notes. CHRIS: That was just the first chapter? STEPH: Yeah, that was just the first chapter. CHRIS: My goodness. STEPH: And I shortened it drastically. [laughs] CHRIS: Okay. All right, off to the races. But I think the summary that you gave there, particularly these are true when you're managing folks but also to manage yourself and to manage up, like, this is relevant to everyone in some capacity in some shape or form. And so that feels very true. STEPH: I will include one more fun aspect from the book, and that's circling back to the humans' core needs at work. And she references Paloma Medina, a coach, and trainer who came up with this acronym. The acronym is BICEPS, and it stands for belonging, improvement, choice, equality, predictability, and significance. And then details how each of those are important to us in our work and how when one of those feels threatened, then that can lead to some problems at work or just even in our personal life. But the fun example that she gave was not when there's a huge restructuring of the organization and things like that are going on as being the most concerning in terms of how many of these needs are going to be threatened or become vulnerable. But changing where someone sits at work can actually hit all of these, and it can threaten each of these needs. And it made me think, oh, cool, plus-one for being remote because we can sit wherever we want. [laughs] But that was a really fun example of how someone's needs at work, I mean, just moving their desk, which resonates, too, because I've heard that from other people. Some of the friends that I have that work in more of a People Ops role talk about when they had to shift people around how that caused so much grief. And they were just shocked that it caused so much grief. And this explains why that can be such a big deal. So that was a fun example to read through. CHRIS: I'm now having flashbacks to times where I was like, oh, I love my spot in the office. I love the people I'm sitting with. And then there was that day, and I had to move. Yeah, no, those were days. This is true. STEPH: It triggered all the core BICEPS, all the things that you need to work. It threatened all of them. Or it could have improved them; who knows? CHRIS: There were definitely those as well, yeah. Although I think it's harder to know that it's going to be great on the way in, so it's mostly negative. I think it has that weird bias because you're like, this was a thing, I knew it. I at least understood it. And then you're in a new space, and you're like, I don't know, is this going to be terrible or great? I mean, hopefully, it's only great because you work with great people, and it's a great office. [laughs] But, like, the unknown, you're moving into the unknown, and so I think it has an inherent at least questioning bias to it. STEPH: Agreed. On that note, shall we wrap up? CHRIS: Let's wrap up. The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeee!!!!!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

The Bike Shed
338: Meticulously Wrong

The Bike Shed

Play Episode Listen Later May 17, 2022 45:52


Chris switched from Trello over to Linear for product management and talks about prioritizing backlogs. Steph shares and discusses a tweet from Curtis Einsmann that super resonated with the work she's doing right now: "In software engineering, rabbit holes are inevitable. You will research libraries and not use them. You'll write code just to delete it. This isn't a waste; sometimes, you need to go down a few wrong paths to get to the right one." This episode is brought to you by BuildPulse (https://buildpulse.io/bikeshed). Start your 14-day free trial of BuildPulse today. Linear (https://linear.app/) Curtis Einsmann Tweet (https://twitter.com/curtiseinsmann/status/1521451508943843329) Louie Bacaj Tweet (https://twitter.com/LBacaj/status/1478241322637033474?s=20) Become a Sponsor (https://thoughtbot.com/sponsorship) of The Bike Shed! Transcript: AD: Flaky tests take the joy out of programming. You push up some code, wait for the tests to run, and the build fails because of a test that has nothing to do with your change. So you click rebuild and you wait. Again. And you hope you're lucky enough to get a passing build this time. Flaky tests slow everyone down, break your flow and make things downright miserable. In a perfect world, tests would only break if there's a legitimate problem that would impact production. They'd fail immediately and consistently, not intermittently. But the world's not perfect, and flaky tests will happen, and you don't have time to fix them all today. So how do you know where to start? BuildPulse automatically detects and tracks your team's flaky tests. Better still, it pinpoints the ones that are disrupting your team the most. With this list of top offenders, you'll know exactly where to focus your effort for maximum impact on making your builds more stable. In fact, the team at Codecademy was able to identify their flakiest tests with BuildPulse in just a few days. By focusing on those tests first, they reduced their flaky builds by more than 68% in less than a month! And you can do the same because BuildPulse integrates with the tools you're already using. It supports all the major CI systems, including CircleCI, GitHub Actions, Jenkins, and others. And it analyzes test results for all popular test frameworks and programming languages, like RSpec, Jest, Go, pytest, PHPUnit, and more. So stop letting flaky tests slow you down. Start your 14-day free trial of BuildPulse today. To learn more, visit buildpulse.io/bikeshed. That's buildpulse.io/bikeshed. CHRIS: Good morning, and welcome to Tech Talk with Steph and Chris. Today at the top of the hour, it's tech traffic hits. STEPH: Ooh, tech traffic. [laughs] I like that statement. CHRIS: Yeah. The Git lanes are clogged up with...I don't know. I got nothing. STEPH: [laughs] Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Steph Viccari. CHRIS: And I'm Chris Toomey. STEPH: And together, we're here to share a bit of what we've learned along the way. So, hey, Chris, what's new in your world? CHRIS: What's new in my world? Actually, I have a specific new thing that I can share, which is, as of the past week, I would say, switched from Trello over to Linear for product management. It's been great. It was a super straightforward transfer. They actually had an importer. We lost some of the comment threads on the Trello cards. But that was easy enough to like each Linear ticket has a link back to Trello. So it's easy enough to keep the continuity. But yeah, we're in a whole new world, a system actually built for maintaining a product backlog, and, man, it shows. Trello was a bunch of lists and cards and stuff that you could link between, which was cool. But Linear is just much more purpose-built and already very, very nice. And we're very happy with the switch. STEPH: I feel like you came in real casual with that news, but that is big news, that you did a switch. [laughter] CHRIS: How are you going to bury the lead like that? You switched project management...[laughter] I actually didn't think it was...I'm excited about it but low-key excited, which is weird because I do like productivity and task management software. So you would think I would be really excited about this. But I've also tried enough of them historically to know that that's never going to be the thing that actually makes or breaks your team's productivity. It can make things worse, but it can't make you great. That's the thing that I believe. And so it's a wonderful piece of software. I'm very excited about it but -- STEPH: Ooh, I like that. It can make you worse, but it doesn't make you great. That's so true, yeah, where it causes pain. Well, and it does make sense. You've been complaining a bit about the whole login with Trello and how that's been frustrating. But I haven't even heard of Linear. That's just...that's, I mean, you're just doing what you do where you bring that new-new. I haven't heard of Linear before. CHRIS: I try to live on the cutting edge. Actually, I deeply try to not live on the cutting edge at this point in my life. That early adopter wave, no, no, no, that's not for me anymore. But I've known a few folks who've moved to Linear. And everyone that I've spoken to who has moved to it has been like, "Yeah, it's been great." I've not heard anything negative. And I've heard or experienced negative things about every other product management tool out there. And so, it seemed like an easy thing. And it was a low-cost enough switch in terms of opportunity costs or the like, it took the effort of someone on our team moving those cards over and setting up the new system and training, but it was relatively straightforward. And yeah, we're super happy with it. And it feels different now. I feel like I can see the work in a different way which is interesting. I think we had brought in a Chrome extension for Trello. I think it's like Hello Epics or something like that that allows...it abuses the card linking functionality in Trello and repurchases that feature as an epic management thing. But it's quarter-baked is how I would describe it, or it's clearly built on top of existing things that were not intended to be used exactly in that way. So it does a great job. Hello Epics does a great job of trying to make something like parent-child list management stuff happen in Trello. But it's always going feel like an afterthought, a secondary feature, something that's bolted on. Whereas in Linear, it's like, no, no, we absolutely have the idea of projects, of course, and you can see burndown charts and things. And the thing that I do want to be careful about is not leaning too much into management. Linear has the idea of cycles or sprints, as many other folks think of them, or iterations or whatever you want to call them. But we've largely not been working in that mode. We've just continued to work through the next up list; that's it. The next up list should be prioritized and well defined at the top and roughly in priority order. So just pick up the next card and work on it. And we just do that every single day. And now we're in a piece of software that has the idea of cycles, and I'm like, oh, this is vaguely interesting. Do we want to do that? Oh, but if you're going to do that, you probably do some estimation, right? And I was like, oh no, now we're into a place that's...okay, I have feelings. I got to decide how to approach that. And so, I am intrigued. And I wonder if we could just say like ten carts that's how many come into a cycle, and that's it. And we use the loosest heuristics possible to define how we structure a cycle so that we don't fall into the trap of, oh, what's our roadmap going to look like six months from now? JK, what's anything going to look like six months from now? That's not a knowable fact. STEPH: I was just thinking where you said that you're moving into sprints or cycles, and then there's that push, well, now you got to estimate. And I just thought, do you? Do you have to estimate? [laughs] CHRIS: We need a burndown chart through 2024, and it must be meticulously accurate down to the hour. STEPH: I think meticulously wrong is how that goes. [laughs] CHRIS: Which is the best kind of wrong. If you're going to be wrong, be meticulous about it. STEPH: Be thorough about it. [laughs] Yeah, the team that I'm on right now, we have our bi-weekly planning, and we go through the board, and we pull stuff in. But there's never a discussion about estimation. And I hadn't really appreciated that until just now. How we don't think about how long is this going to take? We just talked about, well, what's in-flight? And how much work do people still have going on? And then here's the list of things we can pull in. But there's always a list that you can go back to. Like, it's very...we pull in the minimum and knowing that if we run out of work, there's another place to go where there's stuff that's organized. And I just love that cadence, that idea of like, let's not try to make guesses about the future; let's just have it lined up and ready for us to go when we're ready to pull it in. Although I know, that's also coming from a very developer's perspective, and there are product managers who are trying to communicate as to when features are going to get out into the world. So I get that there's a balance, but I still have strong feelings and hesitations around estimating work. CHRIS: Well, I feel like there is a balance there. And so many things in history are like, well, this is an overcorrection against that, and that's an overcorrection against this. And the idea that we can estimate our work that far out into the future that's just obviously false to me based on every project I've ever worked on that has tried to do it. And it has always failed without question. But critically, there is the necessity to sync up work and like, oh, marketing needs to plan the launch of this feature, and it's a critical one. What's it going to look like? When's it going to be ready? You know, we're trying to go for an event, it's not just know...we developers never estimate anything past the immediate moment where like, that's not acceptable. We got to find a middle ground here. But where that middle ground is, is interesting. And so, just operating in the sort of we do work as it comes up is the easiest thing because no one's lying about anything at that point. But sometimes you got to make some guesses and make some estimations. And then it gets into the murky area of I believe with 75% confidence that in three weeks, we will have this feature ready. But to be clear, I said with 75% confidence that means one-quarter of the time; we will not be there at that date. What does that mean? What does that failure mode look like? Let's talk about that. And can you have honest, open, transparent, useful conversations there? That's the space that it becomes more subtle if you need to do that. STEPH: You're reminding me of a conversation that I had with someone where they shared with me some very aggressive team goals. And it was a very friendly conversation. And they're like, "How do you feel about aggressive goals?" And I was like, "Well, it depends. How do you feel about aggressive failure?" Because then once I know where you stand there, then we can talk about aggressive goals. Now, if we're being aggressive, but then we fail to achieve that, and it's one of those, okay, we didn't meet the goal that we'd expected, but everything is fine, and it's not a big deal, then I am okay. Sure, let's shoot for the stars. But if it's one of those, we are communicating these goals to the outside world, and it's going to become incredibly important that we meet these goals, and if we don't, then things are going to go on fire, people are going to be in trouble, and it's just going to be awful, then let's not set aggressive goals. Let's not box ourselves into a space where we are setting ourselves up to fail or feel pain in a meaningful way. I agree that estimations are important, especially in terms of you need to collaborate with other departments, and then also just to provide some sense of where the product is headed and when things may be released. I think estimations then just become problematic when they do become definite, and they're based on so many unknowns, and then when I don't know is not an answer. So if someone asked, "What's your estimate for this?" And the very honest real answer is I don't know, like, we haven't done this type of work before, or these are all the unknowns, and then someone's like, "Well, let's just put an estimation of like two weeks on it," and they just sort of try to force-fit it into being what they want, then that's where it starts to just feel incredibly problematic. CHRIS: Yeah, estimation is a very murky area that we could spend entire episodes talking about, and in fact, I think we have a handful of times. So with that, Linear has been great. We're going to see just how much or how little estimation we actually want to do. But it's been a very nice addition to the toolset. And I'll let you know as we deepen our usage of it what the experience is like, but that's the main thing that's new in my world. What's new in your world? STEPH: Well, before we bounce over to my world, you said something that has intrigued me that has also made me start reflecting on some of the ways that I like to work. And you'd mentioned that you have this prioritized backlog that people are pulling tickets from. And I don't know exactly if there's a planning session or how that looks, but I have recognized that when I am working with a team, and we don't have any planning session, if everybody is just pulling from this backlog, that's being prioritized by someone on the team, that I find that a bit overwhelming. Because the types of work being done can vary so drastically that I find I'm less able to help my colleagues or my teammates because I don't have the context for what they're working on. It surprises me. I'm like, oh, I didn't even know we're working on that feature, or I don't have the context for what's the problem that we're trying to solve here. And it makes it just a lot harder to review and then have conversations with them. And I get overwhelmed in that environment. And I've recognized that about myself based on previous projects that were more similar to that versus if I'm on a project where the team does get together every so often, even if it's high level to be like, hey, here's the theme of the tickets that we're working on, or here's just some of the stuff, then I feel much more prepared for the work that is coming in and to be able to context switch and review. And yeah, so I've kind of learned that about myself. I'm curious, are you similar, or how does that work for you? CHRIS: I'm definitely similar. And I think probably the team is closer to what you're describing. So we do have a planning session every week, just a quick 30-minute scan through the backlog, look at the things that are coming up and also the larger themes. Previously, Epics and Trello now projects and Linear. But talking about what are the bigger pieces of work that we're moving on, and then what are the individual tickets associated with that that we'll be expecting to work on in the next week? And just making sure that everyone has broad clarity around what that feature set is. Also, we're a very small team at this point. Still, we're four people total, but one of the developers is on a break for a couple of weeks this summer. And so there are really only three of us that are driving on the code. And so, with three of us working on the projects, we try very intentionally to have significant overlap between the various...like, we don't want any one person to own any portion of things at this point. And so we're doing a good amount of pairing to cross-pollinate and make sure everyone's...not everyone's aware of everything, but at least one other person is sufficiently aware of everything between the three of us. And I think that's been working well. I don't think we have any major gaps, save for the way that we're doing our mobile architecture that's largely managed by one of the developers on the team and a contractor that we're working with to help do a lot of the implementation. That's a known we chose to silo that thing. We've accepted the cost of that for now. And architecturally, the rest of us are aware of it, but we're not like in the Swift code writing anything because I don't know how to write Swift at this point. I'd love to learn it. I hear good things about the language. [12:26] So yeah, I think conceptually very similar to what you're describing of still want to have people be able to review. Like, I don't want to put up a PR and people be like, I don't know, that looks like code, I guess. I'm not sure what it does. Like, I want it to be very...I want us all to be roughly on the same page, and thus far, we are. As the team grows, that will become trickier to maintain because there are just inherently probably more things that are moving, more different feature areas and surface area that we're tackling in any given week, or there are different ways to approach that. I know you've talked about having a limited number of themes for a given cycle, so that's an idea that can pop up. But that's something that we'll figure out as we get further. I think I'm happy with where we're at right now, so yeah, that's the story there. STEPH: Okay, cool. Yeah, all of that resonates with me, and thinking about it a little more deeply in this moment, I'm realizing I think something you said helped me put this together where when I'm reviewing someone's change, I'm not necessarily just looking to see does your code work? I'm going to trust you that your code works. I may have thoughts about design and other things, but I really want to understand more what's the change to the product that we're making? What's the goal that we're looking to achieve? How are we measuring this? And so if I don't have that context, that's what contributes to that feeling of like, hard context switching of not just context switching, but now I have to level myself up to then understand the problem that's being solved by this. Versus had I known some of the themes going into that particular cycle or sprint, I would have felt far more prepared for that review session versus having to then dig through all the data and/or tickets or talk to someone. Well, switching back to what's going on in my world, I have a particular tweet that I want to share, and it's one that Joël Quenneville brought to my attention. And it just resonates so much with all the type of work that I'm doing right now. So I'm going to read the tweet, and then we'll link to it in the show notes as well. But it's from Curtis Einsmann, and Curtis wrote: "In software engineering, rabbit holes are inevitable. You will research libraries and not use them. You'll write code just to delete it. This isn't a waste; sometimes, you need to go down a few wrong paths to get to the right one." And that describes all the work that I'm doing right now. It's a lot of exploratory, a lot of data-driven work, and finding ways that we can reduce the time that it takes to run RSpec on CI. And it also ties in nicely to one of the things that I think we talked about last week, where we discovered that a number of files have a high runtime variance. And I've really dug into the data there to understand, okay, is it always specific files that have these high runtime variants? Are there any obvious contributions to what's causing this? Are we making real network calls that then could sometimes take a long time to return? And the result is there's nothing obvious. They're giant files. The number of SQL commands that are being run for each file varies drastically. They're all high, but it's still very different. There's no single fact about these files that has really been like, yes, this is what's causing these files to have such a runtime variance. And so while I've been in the data, I'm documenting it, and I'm making a list and putting it all together in a ticket so at least it's there to look at later. But I'm going to move on. It's one of those I would love to know what's causing this. I would love to address it because it would put us in an ideal state for how we're distributing tests, which would have a significant impact on our runtime. But it also feels a little bit like chasing my tail because I'm worried, like with some of the other experiments that we've done in the past where we've addressed tentpoles, that as soon as you address the issue for one or two files, then other files start having the same problem. And you're just going to continue to chase and chase, and I don't want to be in that. So upfront, this was one of those; hey, let's look at the data. If there's something obvious, let's address it; if not, move on. So I'm at that point today where I'm wrapping up all of that data, and then I'm going to move on, move on to the next thing. CHRIS: There's deep truth in that tweet that you shared at the start of this segment. The idea like if we knew the work that we had to do at the front, yeah, we would just do that, but often, we don't. And so, being able to not treat it as a failure when something doesn't work out is, I think, so critical. I think to expand on the idea just a tiny bit, the idea of the scientific method, failure is totally an option and is part of science. I remember watching MythBusters, and Adam Savage is just kind of like, "Failure is always an option," and highlighting that as part of it. Like, it's an outcome. You've learned something. You have a new data point. You can take that and then carry it forward with you. But it's rough in the moment. And so, I do think that this is a worthwhile thing to meditate on. And it's something that I've had to revisit a handful of times in my career of just like, man, I feel like I've just been spinning my tires all week. I'm like, we know what we want to get done, but just each approach I take isn't working for one reason or another. And then, finally, you get to the end. And then you've got this paragraph-long summary of all the things that didn't work in your PR and one-line change sort of thing. And those are painful, but they're part of the game. Like, that is unavoidable. I have not found a way to just know how to do the work upfront always. I would love that. I would sign up for whatever seminar was selling that. I wouldn't. I would know that that seminar is a lie, actually. But broadly, I'm intrigued by the idea if someone were selling that, I'd be like, well, I mean, pitch me on it. Tell me why I should believe you; I don't, just to be clear. But yeah. STEPH: This project has really helped me embrace always setting a goal or a question upfront about what I'm wanting to achieve or what I'm looking to answer because a number of times while Joël and I have been spelunking through data...And then so originally, with the saga, we started out with why doesn't our math match reality? We understand that if these tests are distributed perfectly across the CPUs, then that should cut the runtime in half. But yet, we weren't seeing that even though we had addressed the tentpoles. So we dug into understanding why. And the answer is because they're not perfectly distributed, and it's because of the runtime variance. And that was a critical moment to look back and say, "Did we achieve the goal?" Yes, we identified the problem. But once you see a problem, it's just so easy to dig in and keep going. It's like, well, now I want to know what's causing these files to have a runtime variance. But it's one of those we achieved our goal. We acknowledged upfront that we wanted to at least understand why. Let's make a second decision, do we keep going? And I'm at that point where, frankly, I probably dug in a little more than I should because I'm stubborn. But I'm recognizing that now's the time to back away and then go back and move on to the next high-priority item, which is converting for funsies; I'll share. The next thing is converting Test::Unit test over to RSpec because we have, I think, around 25 tests that are written in Test::Unit. And we want to move them over to RSpec because that particular just step in the build process takes a good three to four minutes. And part of that is just booting up Rails and then running the tests very fast. And we're underutilizing the machine that's running them because it's only 25 tests, but there are 86 CPUs to run it. So we'd really like to combine those 25 tests with the rest of the RSpec suite and drop that step. So then that should add minimal time to the overall build but then should take us down at least a couple of minutes. And then also makes it easier to manage and help folks so that way, there's one consistent testing framework that's in use versus having to manage some of these older tests. CHRIS: It's funny; I think it was just two episodes back where we talked about why RSpec, and I think both of us were just like, well yeah. But I mean, if there are tests and another, like, it's fine, you just leave them with the exception that if there's like 2% of our tests are in Test::Unit, and everything else is in RSpec, yeah, maybe that that conversion efforts seem totally worth it. But again, I think as you're describing that, what I'm hearing is just like the scientific method, just being somewhat structured in the approach to what's the hypothesis? And what's the procedure we're going to use to determine if that hypothesis is true or false? And then what do we do? And then what are the results? And then you just do that on loop. But being not just sort of exploring. Sometimes you have to be on exploratory mode. But I definitely find that that tiny bit of rigor of just like, wait, okay, before I actually do anything, what do I think is going on here? What's my guess? And then, okay, if that guess were true, what would I be able to observe in the world? Okay, here we go. And just that tiny bit of structure is so...it sometimes feels highly formal to go into that mode and be like, no, no, no, let me take a step back. Let me write down my thoughts. I'm going to have a little checklist and do the thing. But I've never regretted doing it. I will say that. I have deeply regretted not doing it. I feel like I should make a list of things that fit that structure. I've never regretted committing in Git ever. That's been great. I've always been able to unwind it, but I've never been able to not unwind it or the opposite. I've regretted not committing. I have not regretted committing. I have regretted not writing out my hypothesis or approach. I have not regretted doing it. And so, yeah, this feels like it falls firmly in that category of like, it's worth just a tiny bit of structure. There's a reason it is the scientific method. STEPH: Yeah, I agree. I've not regretted documenting upfront what it is I look to achieve and how I think I'm going to answer the question. That has been immensely helpful. Because then I also forget, like, two weeks ago, I'll be like, wasn't there a question around why this was happening, and I need to understand? And all of that was so context-heavy that as soon as I'm out of the thick of it, I completely forget it. So if I care about it deeply or if I want to be able to revisit it, then I need to document it for myself. It's given me a lot of empathy for people who do more scientific research around, oh my gosh, like, you have to document everything you do and then still be able to prove it five years from now or however long. I'm just throwing out numbers. And it needs to be organized enough that someone, if they do question your research that, then you have it there. My research documents would not withstand scrutiny at this point because they are still just more personal notes. But yes, it's given me a lot of empathy and respect for people who do run very serious research, experiments, and trials, and then have to be able to prove it to the world. Pivoting just a bit, there's a particular topic that resonated with both you and I; in fact, it's a particular tweet. And, Louie, I do apologize if I mispronounce your last name, but Louie Bacaj. And we'll include a link in the show notes to the tweet, but Louis shared, "I managed multiple engineering teams before quitting tech. Now that I quit, I can speak freely. Here are 12 things your manager may not be telling you, but I know for a fact will help you." So there are a number of interesting discussions and comments that are in this thread. The one thing in particular that really caught my attention is number 10, and it's "Advocate for junior developers." So they said that their friend reminded them that just because you don't have 10-plus years of experience does not mean that they won't be good. Without junior engineers on the team, no one will grow. Help others grow; you'll grow too. And that's the part that I love so much is that without junior engineers on the team, no one will grow because that was very thought-provoking for me. It's something that I find that I agree with deeply, but I hadn't really considered why I agree with that so much. So I'm excited to dive into that topic with you. And then, as a second topic to go along with that is, can juniors start with a remote team? I think that's one of the other questions when you and I were chatting about this. And I'm intrigued to hear your thoughts. CHRIS: A bunch of stuff there. Starting with the tweet, I love elements of this. Some of it feels like it's intentionally somewhat provocative. So like, without junior engineers on the team, no one will grow. That feels maybe a little bit past the bar because I think we can technically grow, and we can build things and whatnot. But I think what feels deeply true to me is truly help others grow; you'll grow too. The act of mentoring, of guiding, of training, of helping someone on their journey will inherently help you grow and, I think, change the way that you think about the work. I think the beginner mind, the earlier in the career folks coming into a codebase, they will see things fundamentally differently in a really useful way. It's possible that along your career, you've just internalized things. You've been like, yeah, no, that was weird. But then I smashed my head against it for a while, and now I understand this thing. And it just makes sense to me. But it's like, that thing actually doesn't make sense. You have warped your mind to match the thing, not, quote, unquote, "come to understand it." This is sounding too judgmental to people who've been in the industry for a while, but I found this of myself. Or I can just take for granted things that took a long time to adapt my head to, and if anything, maybe I should have pushed back a little more. And so, I find that junior engineers can be a really fantastic lens for the complexity of a project. Like, the world is truly a complex place, and that's just true. But our job as software engineers is to tame that complexity and manage it. And so, I love the mindset that can come or the conversations that can come out of that. And it's much like test-driven development is a pressure on the complexity of your code, having junior engineers join the team and needing to explain how all of the different features work, and what the overall architecture is, and the message passing under this and that, it's a really useful conversation to have. And so that "Help others grow; you'll grow too" feels deeply, deeply true to me. STEPH: Yeah, I couldn't agree more in regards to how juniors really help our team and especially, as you mentioned, with complexity and ¬having those conversations. Some of the other things that have come to mind for me as well around the importance of having junior developers on your team...and maybe it's not specifically they're junior developers but that you just have a variety of experience on your team. It's going to help you lean into a culture of learning because you have people that are at different stages of their career. And so you want an environment where people can learn together, that they can fail together, and they can be public about it. And having people that are at different stages of their career will lead, well, at least ideally, it'll lead to more pair programming. It's going to lead to more productive code reviews because then people can ask more questions around why did you choose this, or why are you doing that? Versus if everybody is at the same level, then they may just intuitively have reasons that they think someone did something. But it takes someone that's a bit new to say, "Hey, why did you choose this?" or to bring up some other ideas or ways that they could pursue it. They may bring in new ideas for, like, why has the team always done something this way? Let's think about new ways that we could do this. Or maybe this is really unfriendly, the way that we're doing this, not just for junior people but for people that are new to the team. And then there's typically less knowledge siloing because then you're going to want to pair the newer folks with the more experienced folks. So that way, you don't have this more senior developer who's then off in a corner working by themselves. And it's going to improve your communication skills. There's just...I realized I'm just rambling because I feel like there are so many benefits that go along with having a variety of people on your team, especially in terms of experience. And that just leads to such a better learning environment and, ultimately, better software and better products. And yet, I find that so many companies won't embrace people that are newer to software. They always want the senior developers. They want the 10x-er or whatever those are. They want the people that have many, many years of experience. And there's so much value that comes from mentoring the next group of developers. And it's incredibly frustrating to me that one, companies often aren't open to it. But honestly, more than that, as long as you're upfront and honest about like, hey, this is the team that we need right now to build what we're looking to build, I can get past that; I can understand that. But please don't then mislead people and say that you're a junior-friendly team, and then not be prepared. I feel like some teams will go so far as to say, "Yes, we are junior-friendly," and they may even tweak their interview process to where it is a bit more junior-friendly. But then, by the time that person joins the team, they're really not prepared. They don't have an onboarding plan. They don't have a mentorship plan. And then they fail that person because that person has worked hard to get there. And they've worked hard to bring that person onto the team, but then they don't have a plan from there. And I've seen it too many times. And it just frustrates me so much because it puts that junior person in such a vulnerable state where they really have to be an incredible self-advocate to then overcome those hurdles from a lack of preparation on that company's part. Okay, I think that's my event. I'm sure I could vent about this a lot more, but I will cut it off there. That's the heart of it. CHRIS: I do think, like, with anything else, it's something that we have to be intentional about. And so what you're saying of like, yeah, we're a junior-friendly company, but then you're just hiring folks, trying to find folks that may work at a slightly lower pay grade, and that's what that means to you. So like, no, no, that's not what this is. This needs to be something different. We need to have a structure and an organization that can support folks at different points in their career. But it's interesting to me to think about the sort of why of it. And the earlier part of this conversation, we talked about some of the benefits that can come organizationally from it, and I do sincerely believe in that. But I also believe that it is fundamentally one of the best ways to find really talented people early on in their career and be in a position to hire them where maybe later on in their career, that just wouldn't happen naturally. And I've seen this play out in a number of organizations. I went to Northeastern University for my college, and Northeastern is famous for the co-op program. Northeastern sounds really fancy. Now I learned that they have like a 7% acceptance rate for college applications right now, which is wildly low. When I went to Northeastern, it was not so fancy. So just in case anyone's hearing that and they're like, "Oh, Northeastern, wow." I'm not that fancy. [laughs] But they did have the co-op then, and they still have it now. And the co-op really is a differentiating thing. You do three six-month rotations. And it is this fundamental differentiator in terms of when you're graduating. Particularly, I was in mechanical engineering. I came out, and I actually knew what that meant in the world. And I'd used Outlook, and I knew what a water cooler was and how to talk near one because that's a critical thing to learn in the world. And really transformative experience for me. But also, a thing that I observed was many of my friends ended up working at companies that they had co-opted for. I'm one of those people. I would say more than 50% of my friends ended up with a position at a company that they had done a co-op rotation with. And it really worked out fantastically. That organization and the individual got to try things out, experience. And then, I ended up staying at that company for a number of years, and it was a wonderful experience. But I don't know that I would have ended up there otherwise. That's not necessarily the way that would have played out. And similarly like, thoughtbot has the apprenticeship. And I have seen so many wonderful developers start at that very early point in their career. And there was this wonderful structure around them joining the thoughtbot team, intentional, structured, supported. And then those folks went on to be some of the most talented developers that I've ever worked with at a wonderfully talented organization. And so the story of like, you should do this, organizations. This is a thing that you should invest in for yourself, not just for the individual, like, for both. Everybody wins in this case, in my mind. I will say, though, in terms of transparency, I currently manage a team of three developers. And we hired very intentionally for senior folks this early on in where we're at. And that was an intentional choice because I do believe that if you're going to be hiring more junior developers, that needs to be something that you do very intentionally, that you have a support structure in place, that you're able to invest the time in where they're at and make sure we have sort of... I think a larger team makes more sense to bring juniors into broadly. That's the thing that I'm saying out loud that I'm like, I should push on that a little bit. Is that true? Do I really believe that? But I think so, my actions obviously point to it. But it is an interesting trade-off space of how do you think about that? My hope is that as we grow as an organization, that we would then very intentionally start hiring folks in a more junior, mid-level to junior and be very intentional about how we support them, bring them into the organization, et cetera. I do believe it is a win-win situation for everyone when done with intention and with focus. STEPH: That's such an interesting bit that you just said because I very much appreciate when companies recognize do we have the bandwidth to support someone that's more junior? Because at thoughtbot, we go through periods where we don't have our apprenticeship that's open because we recognize we're not in a place that we can support someone. And we don't want to bring someone in unless we can help them be successful. I very much admire that and appreciate that about companies when they can perform that self-assessment. I am so intrigued. You'd mentioned being a smaller team. So you more intentionally hire senior developers. And I think that also makes sense because then you need to build up who's going to be in that mentorship pool? Because then people could leave, people could take vacations, and so then you need to have that support system in place. But yeah, I don't know what that then perfect balance is. It's like, okay, so then as soon as you have like five people available to mentor or interested in mentorship, it's like, then do you start bringing in the conversation of like, let's bring in someone that we can help build up and help them be successful and join our team? And I don't know what that magical number is. I do think it's important for teams to reflect to say, "Can we take on someone that's junior?" All the benefits of having someone that's junior. And then just being very honest and then having a plan for once that junior person does arrive. What does their career path look like while they've joined that team, and who's going to be that person that's going to help them level up? So not only make that choice upfront of yes, we are bringing someone on but let's also think about like the first six months of their work here at the company and what that's going to look like. It feels like an important step that a lot of companies fail to do. And I think that's why there are so many articles that then are like, hey, if you're a junior dev, here's all the things that you should do to be the best junior dev. That's fabulous. And we're constantly shoring up junior devs to be like, hey, here's all the things that you need to be great at. But we don't have as many conversations around; hey, here's all the things that your manager or the rest of your team should be great at to then support you equally as you are also doing your best to meet them. Like, they need to meet you halfway. And I'm not completely unsympathetic to the plight; I understand. It's often where I've seen with teams the more senior developers that have very strong mentorship communication skills are then also the teammates that get pulled into all the meetings and all the different projects, so then they are less available to be that mentor. And then that's how this often fails. So I don't think anybody is going into this intentionally, but yet, it's what happens for when someone is new and joining a team, and it hasn't been determined the next six months what that person's onboarding and career path looks like. Circling back just a bit, there's the question around, can juniors start with a remote team? I can go first. And I'm going to say unequivocally yes. There's no reason a junior can't start with a remote team. Because all the things that I feel strongly about come down to how is your team going to plan for this person? And how are they going to support this person? And all the benefits that you get from being in an office with a team, I think those do exist. And frankly, for someone like myself, it can be easier to establish a bond with someone that you get to see each day, get to see in person. You can walk up to their desk and can say, "Hey, I've got a question for you." But I think all those benefits just need to be transferred into a remote-friendly way. So I think it does ratchet up how intentional you have to be with your team and then onboarding a junior developer. But I absolutely think it's doable, and we should do it. CHRIS: You went with unequivocally yes as your answer. I'm going to go with a qualified maybe as my answer. I want this to be true, and I think it can be true. But I think it takes all the more intentionality than even what we've been describing. To shift the question around a little bit, what does remote work mean? It doesn't just mean we're doing the work, but we're separate. I think remote work inherently is at its best when we also are largely async first. And so that means more structured writing. The nature of the conversation tends to be more well-formed in each interaction. So it's like I read a big document, and then I pass it over to you. And at your leisure, you respond to it with a bunch of notes, and then it comes back to me. And I think that mode of interaction, while absolutely wonderful and something that I love, I think it fits really well when you're a little bit further on in your career when you understand things a little bit better. And I think the dance of conversation is more useful earlier on and so forth. And so, for someone who's newer to a team, I think having the ability to ask a quick question over and over is really useful to someone who's early on in their career. And remote, again, I think it's at its best when it's async. And those two are sort of at odds. And so it's that mild tension that gives me pause of like, something that I think that makes remote work great I do think is at least a hurdle that you would have to get over in supporting someone who's a little bit newer. Because I want to be deeply present for someone who's newer to their journey so that they can ask a lot of questions so that I am available to be interrupted regularly. I loved at thoughtbot sitting next to someone and being their mentor and being like, yeah, anytime you want, just tap on my desk. If I got my headphones on, that doesn't mean I'm ignoring you; it means I just need to make the sounds go away for a minute because that's the only way my brain will work. But feel free to just tap on my desk or whatever and grab my attention for a moment. And I'm available for that. That's an intentional choice. That's breaking up my continuity of the day, but we're choosing that for a reason. I think that's just a little harder to do in a remote context and all the more so if we're saying, hey, we're going to try this async thing where we write structured documents, and we communicate in these larger, more well-formed, communicates back and forth. But I do believe it can be done. I think it should be done. I just think it's all the harder for all of those reasons. STEPH: I agree that definitely makes it harder. But I'm going to push a little bit and say that when you mentioned being deeply present, I think we can be deeply present with someone and be remote. We can reduce the async requirements. So if you are someone that is more senior or more accustomed to the team, you can fall back to more of those async ways to communicate. But if someone is new, and needs more mentorship, then let's just set up time where we're going to literally hang out for a couple of hours each day or whatever pairing environment works best for them because pairing can also be exhausting. But hey, we're going to have a check-in each day; maybe we close out each day and touchpoint. And feel free to still message me and interrupt me. Like, you're going to just heighten your availability, even though it is remote. And be aware, like, hey, this person could message me at more times, and I'm okay with that. I have opted into this form of communication. So I think we just take that mindset of, hey, there's this person next to me, and I'm their mentor to like, hey, they're not next to me, but I'm still their mentor, and I'm still here for them. So I agree that it's harder. I think it falls on us and the team and the mentors to change ourselves versus saying to juniors, "Hey, sorry, it's remote. That's not going to work for you." It totally works for them. It's us, the mentors, that need to figure out how to make it work. I will say being on that mentor side that then not being able to see someone so if they are next to me, I can pick up on body language and facial expressions, and I can tell when somebody's stuck. And I can see that they're frustrated, or I can see that now's a good time for me to just be like, "Hey, how's it going? What are you working on? Or do you need help with something?" And I don't have that insight when I'm away. So there are real challenges like that that I don't know how to address. I have gone the obnoxious route [laughs] where I just message people, and I'm like, "Hey, how's it going? How's it going? How's it going?" And I try not to do that too much. But I haven't found a better way to manage that other than to constantly check in because I do have less feedback from that person that I'm working with unless they are just incredibly open about sharing when they're stuck. But typically, when you're newer to a team or newer to a career, you're going to be less willing to share when you're stuck. But yeah, there are some real challenges, but I still think it's something for us to figure out. Because otherwise, if we cut off access for remote teams to junior folks, I mean, that's where we're headed. There are so many companies and jobs that are headed remote that not being junior friendly and being remote in my mind is just not an option. It's something that we need to figure out. And it's hard, but we need to figure it out. CHRIS: Yeah, 100% on we need to figure that out and that that's on us as the people managing and structuring and bringing folks into teams. I think my stance would be like, let's just be clear that this is hard. It takes effort to make sure that we've provided a structure in which someone newer to a team can be successful. It takes all the more effort to do so in a remote context, I think. And it's that recognition that I think is critical. Because if we go into this with the wrong mindset, it's like, oh yeah, it's great. We got this new person on the team. And yeah, they should be ready to go in like two weeks, right? It's like, no, no, this is a different thing. We need to be very clear about it. This is going to require that we have someone who is able to work with them and support them in this. And that means that that person's output will likely be a little bit reduced for the period of time that we're talking about. But we're playing a long game here. Let's make sure we're clear on that. This is intentional. And let's be clear, the world of hiring and software right now it's not like super easy. There aren't way more software developers than there are jobs; at least, that's been my experience. So this is something absolutely worth investing in for just core business reasons and also good for people. So hey, it's a win-win. Let's do it. Let's figure it out. But also, let's be clear that it's going to be a little tricky along the way. So, you know, let's be intentional about that. But yeah, obviously do it, got to do it. STEPH: Wait, so I feel like we might have circled back to unequivocally yes. [laughs] Have we gotten there, or are you still on the fence? CHRIS: I was unequivocally yes from the beginning, but I couched it in, but...yeah, I said other things. You're right. I have now come around; let's say to unequivocally yes. STEPH: [laughs] Cool. I don't want to feel like I'm forcing you to agree with me. [laughs] But I mean, we just so rarely disagree. So we've either got to identify this as something that we disagree on, which would be one of those rare occasions like beer and Pop-Tarts. CHRIS: A watershed moment. Beer and Pop-Tarts. STEPH: Yeah, those are the only two so far. [laughter] CHRIS: Not together also. I just want to go on record beer and Pop-Tarts; I don't think would be...anyway. STEPH: Ooh, I don't know. It could work. It could work. CHRIS: Well, there's another thing we disagree on. STEPH: I would not turn it down. If I was eating a Pop-Tart, and you're like, "Hey, you want a beer?" I'd be like, "Sure," vice versa. I'm drinking a beer. "Hey, you want a Pop-Tart?" "Totally." CHRIS: Okay. Well yeah, if I'm making bad decisions, I'm obviously going to chain them together, but that doesn't mean that they're a good decision. It's just a chain of bad decisions. STEPH: I feel like one true thing I know about you is that when you make a decision, you're going to lean into it. So like, this is why you are all about if you're going to have a Pop-Tart, you're going to have the highest sugary junk content Pop-Tart possible. So it makes sense to me. CHRIS: It's the Mountain Dew theorem, yeah. STEPH: I didn't know this had a theorem. The Mountain Dew theorem? CHRIS: No, that's just my name. Well, yeah, if I'm going to drink soda, I'm going to drink Mountain Dew, the nonsense nuclear option of soda. So yeah, I guess you're describing me, although as you say it back to me, I suddenly feel very, like, oh God, is this who I am as a person? [laughs] And I'm not going to say you're wrong. I'm just going to spend a little while thinking about some stuff. STEPH: I mean, you embrace it. I think that's lovely. You know what you want. It's like, all right, let's do this. Let's go all in. CHRIS: Thank you for finding a wonderfully positive way to frame it here at the end. But I think on that note, should we wrap up? STEPH: Let's wrap up. CHRIS: The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

The Bike Shed
336: Million Dollar Password

The Bike Shed

Play Episode Listen Later May 3, 2022 35:07


Chris came up with a mnemonic device: Fn-Delete – for when he really wants to delete something and is also thinking about password complexity requirements, which leads to an exciting discussion around security theater. Steph talks about the upcoming RailsConf and the not-in-person option for virtual attendees. She also gives a shoutout to the Ruby Weekly newsletter for being awesome. NIST Password Standards (https://specopssoft.com/blog/nist-password-standards/) 3 ActiveRecord Mistakes That Slow Down Rails Apps: Count, Where and Present (https://www.speedshop.co/2019/01/10/three-activerecord-mistakes.html) Difference between count, length and size in an association with ActiveRecord (https://bhserna.com/count-size-length-active-record.html) Ruby Weekly (https://rubyweekly.com/) Railsconf 2022 (https://railsconf.org/) Become a Sponsor (https://thoughtbot.com/sponsorship) of The Bike Shed! Transcript: STEPH: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Steph Viccari. CHRIS: And I'm Chris Toomey. STEPH: And together, we're here to share a bit of what we've learned along the way. So hey, Chris, happy Friday. You know, each time I do that, I can't resist the urge to say happy Friday, but then I realize people aren't listening on a Friday. So happy day to anyone that's listening. What's new in your world, friend? CHRIS: I'm going to be honest; you threw me for a loop there. [laughs] I think it was the most recent episode where we talked about my very specific...[laughs] it's a lovely Friday, that's true. There's sun and clouds. Those are true things. But yeah, what's new in my world? [laughs] I can do this. I can focus. I got this. Actually, I have one thing. So this is going to be, I'm going to say vaguely selfish, but I have this thing that I've been trying to commit into my brain for a long time, and I just can't get it to stick. So today, I came up with like a mnemonic device for it. And I'm going to share it on The Bike Shed because maybe it'll be useful for other people. And then hopefully, in quote, unquote, "teaching it," I will deeply learn it. So the thing that happens in my world is occasionally, I want to delete a URL from Chrome's autocomplete. To be more specific, because it's easier for people to run away with that idea, it's The Weather Channel. I do not like weather.com. I try to type weather often, and I just want Google to show me the little, very quick pop-up thing there. I don't want any ads. I don't want to deal with that. But somehow, often, weather.com ends up in my results. I somehow accidentally click on it. It just gets auto-populated, and then that's the first thing that happens whenever I type weather into the Omnibox in Chrome. And I get unhappy, and I deal with it for a while, then eventually I'm like, you know what? I'm deleting it. I'm getting it out of there. And then I try and remember whatever magical key combination it is that allows you to delete an entry from the drop-down list there. And I know it's a weird combination of like, Command-Shift-Alt-Delete, Backspace, something. And every single time, it's the same. I'm like, I know it's weird, but let me try this one. How about that one? How about that one? I feel like I try every possible combination. It's like when you try and plug in a USB drive, and you're like, well, it's this way. No, it's the other way. Well, there are only two options, and I've already tried two things. How can I not have gotten it yet? But I got it now. Okay, so on a Mac specifically, the key sequence is Shift-Function-Delete. So the way I'm going to remember this is Function is abbreviated on the keyboard as Fn. So that can be like I'm swearing, like, I'm very angry about this. And then Shift is the way to uppercase something like you're shouting. So I just really need to Fn-Delete this. So that's how I'm going to remember it. Now I've shared it with everyone else, and hopefully, some other folks can get utility out of that. But really, I hope that I remember it now that I've tried to boil it down to a memorable thing. STEPH: [laughs] It's definitely memorable. I'm now going to remember just that I need to Fn-Delete this. And I'm not going to remember what it all is tied to. [laughs] CHRIS: That is the power of a mnemonic device. Yeah. STEPH: Like, I know this is useful in some way, but I can't remember what it is. But yeah, that's wonderful. I love it. That's something that I haven't had to do in a long time, and I hadn't thought about. I need to do that more. Because you're right, especially changing projects or things like that, there are just some URLs that I don't need cached anymore; I don't want auto-completed. So yeah, okay. I just need to Fn-Delete it. I'll remember it. Here we go. I'm speaking this into the universe, so it'll be true. CHRIS: Just Fn-Delete it. STEPH: Your bit about the USB and always getting it wrong, you get it 50-50 [laughs] by getting it wrong, resonates so deeply with me and my capability with directions where I am just terrible whether I have to go right or left. My inner compass is going to get it wrong. And I've even tried to trick myself where I'm like, okay, I know I'm always wrong. So what if I do the opposite of what Stephanie would do? And it's still somehow wrong. [laughs] CHRIS: Somehow, your brain compensates and is like, oh, I know that we're going to do that. So let's...yeah, it's amazing the way these things happen. STEPH: Yep. I don't understand it. I've tried to trick the software, but I haven't figured out the right way. I should probably just learn and get better at directions. But here we are. Here we are. CHRIS: You just loosely referred to the software, but I think you're referring to the Steph software when you say that. STEPH: Yes. Oh yeah, Steph software totally. You got it. [laughs] CHRIS: Gotcha. Cool. Glad that I checked in on that because that's great. But shifting gears to something a little bit deeper in the technical space, this past week, we've been thinking about passwords within our organization at Sagewell. And we're trying to decide what we want to do. We had an initial card that came through and actually got most of the way to implemented to dial up our password strictness requirements. And as I saw that come through, I was like, oh, wait, actually, I would love to talk about this. And so we had the work that was coming through the PR that had been opened was a pretty traditional set of let's introduce some requirements on our passwords for complexity, so let's make it longer. We're going from; I think six was the default that Devise shipped with, so we're increasing that to, I think it was eight. And then let's say that it needs a number, and a special character, and an uppercase letter or something like that. I've recently read the NIST rules, so the National Institute of Standards and Technology, I think, is what they are. But they're the ones who define a set of rules around this or guidelines. But I think they are...I don't know if they are laws or what at this point. But they tell you, "This is what you should and shouldn't do." And I know that the password complexity stuff is on the don't do that list these days. So I was like, this is interesting, and then I wanted to follow through. Interestingly, right now, I've got the Trello boards up for The Bike Shed right now. But as a result, I can't look at the linked Trello card that is on the workboards because they're in different accounts. And Trello really has made my life more difficult than I wanted. But I'm going to pull this up elsewhere. So let's see. So NIST stuff, just to talk through that, we can include a link in the show notes to a nice summary. But what are the NIST password requirements? Eight character minimum, that's great. Change passwords only if there is evidence of a compromise. Screen new passwords against a list of known compromised passwords. That's a really interesting one. Skip password hints, limit the number of failed authentication attempts. These all sound great to me. The maximum password length should be at least 64 characters, so don't constrain how much someone can put in. If they want to have a very long password, let them go for it. Don't have any sort of required rotation. Allow copy and pasting or functionality that allows for password managers. And allow the use of all printable ASCII characters as well as all Unicode characters, including emojis. And that one really caught my attention. I was like, that sounds fun. I wish I could look at all the passwords in our database. I obviously can't because they're salted and encrypted, and hashed, and all those sorts of things where I'm like, I wonder if anybody's using emojis. I'm pretty sure we would just support it. But I'm kind of intrigued. STEPH: You said something in that list that caught my attention, and I just want to see if I heard it correctly. So you said only offer change password if compromised? Does that mean I can't just change my password if I want to? CHRIS: Sorry. Yeah, I think the phrasing here might be a little bit odd. So it's essentially a different way to phrase this requirement is don't require rotation of passwords every six or whatever months. Forgotten password that's still a reasonable thing to have in your application, probably a necessity in most applications. But don't auto-rotate passwords, so don't say, "Your password has expired after six months." STEPH: Got it. Okay, cool. That makes sense. Then the emojis, oh no, it's like, I mean, I use a password manager now, and thanks to several years ago where he shamed me into using one. Thank you. That was great. [laughs] CHRIS: I hope it was friendly shame, but yeah. STEPH: Yes, it was friendly; kind shame if that sounds like a weird sentence to say. But yes, it was a very positive change. And I can't go back now that I have a password manager in my life. Because yeah, now I'm thinking like, if I had emojis, I'd be like, oh great, now I have to think about how I was feeling at the time that then I introduced a new password. Was I happy? Was I angry? Is it a poop emoji? Is unicorn? What is it? [laughs] So that feels complicated and novel. You also mentioned on that list that going for more complexity in terms of you have to have uppercase; you have to have a particular symbol, things like that are not on the recommended list. And I didn't know that. I'm so accustomed to that being requirements for passwords and the idea of how we create something that is secure and less easy to guess or to essentially hack. So I'm curious about that one if you know any more details about it as to why that's not the standard anymore. CHRIS: Yeah, I think I have some ideas around it. My understanding is mostly that introducing the password complexity requirements while intended to prevent people from using very common things like names or their user name or things like that, it's like, no, no, no, you can't because we've now constrained the system in that way. It tends in practice to lead to people having a variety of passwords that they forget all the time, and then they're using the forgotten password flow more often. And it basically, for human and behavior reasons, increases the threat surface area because it means that they're not able to use...say someone has a password scheme in mind where it's like, well, my passwords are, you know, it's this common base, and then some number of things specific to the site. It's like, oh no, no, we require three special characters, so it's like they can't do their thing. And now they have to write it down on a Post-it Note because they're not going to remember it otherwise. Or there are a variety of ways in which those complexity requirements lead to behavior that's actually less useful. STEPH: Okay, so it's the Post-it Note threat vector that we have to be worried about. [laughs] CHRIS: Which is a very real threat factor. STEPH: I believe it. [laughs] Yes, I know people that keep lists of passwords on paper near their desk. [laughs] This is a thing. CHRIS: Yep, yep, yep. The other thing that's interesting is, as you think about it, password complexity requirements technically reduce the overall combinatoric space that the passwords can exist in. Because imagine that you're a password hacker, and you're like, I have no idea what this password is. All I have is an encrypted hashed salted value, and I'm trying to crack it. And so you know the algorithm, you know how many passes, you know potentially the salt because often that is available. I think it has to be available now that I think about that out loud. But so you've got all these pieces, and you're like, I don't know, now it's time to guess. So what's a good guess of a password? And so if you know the minimum number of characters is eight and, the maximum is 12 because that actually happens on a lot of systems, that's actually not a huge combinatoric space. And then if you say, oh, and it has to have a number, and it has to have an uppercase letter, and it has to have a special character, you're just reducing the number of possible options in that space. And so, although this is more like a mathematical thing, but in my mind, I'm like, yeah, wait, that actually makes things less secure because now there are fewer passwords to check because they don't meet the complexity requirements. So you don't even have to try them if you're trying to brute-force crack a password. STEPH: Yeah, you make a really good point that I hadn't really thought about because I've definitely seen those sites that, yeah, constrain you in terms of like, has to have a minimum, has to have a maximum, and I hadn't really considered the fact that they are constraining it and then reducing the values that it could be. I am curious, though, because then it doesn't feel right to have no limit in terms of, like, you don't want people then just spamming your sign up and then putting something awful in there that has a ridiculous length. So do you have any thoughts on that and providing some sort of length requirement or length maximum? CHRIS: Yeah, I think the idea is don't prevent someone who wants to put in a long passphrase, like, let them do that. But there is, the NIST guidelines specifically say 64 characters. Devise out of the box is 128, I believe. I don't think we tweaked that, and that's what we're at right now. So you can write an old-style tweet and that can be your password if that's what you want to do. But there is an upper limit to that. So there is a reasonable upper limit, but it should be very permissive to anyone who's like, I want to crank it up. STEPH: Cool. Cool. Yeah, I just wanted to validate that; yeah, having an upper bound is still important. CHRIS: Yeah, definitely. Important...it's more for implementation and our database having a reasonable size and those sorts of things. Although at the end of the day, the thing that we saw is the encrypted password. So I don't know if bcrypt would run slower on a giant body of text versus a couple of characters; that might be the impact. So it would be speed as opposed to storage space because you always end up with a fixed-length hash of the same length, as far as I understand it. But yeah, it's interesting little trade-offs like that where the complexity requirements do a good job of forcing people to not use very obvious things like password. Password does not fit nearly any complexity requirements. But we're going to try and deal with that in a different way. We don't want to try and prevent you from using password by saying you must use an uppercase letter and a special character and things that make real passwords harder as well. But it is an interesting trade-off because, technically, you're making the crackability easier. So it gets into the human and the technical and the interplay between them. Thinking about it somewhat differently as well, there's all this stuff about you should salt your passwords, then you should hash them. You should run them through a good password hashing algorithm. So we're using bcrypt right now because I believe that's the default that Devise ships with. I've heard good things about Argon2; I think is the name of the new cool kid on the block in terms of password hashing. That whole world is very interesting to me, but at the end of the day, we can just go with Devise's defaults, and I'll feel pretty good about that and have a reasonable cost factor. Those all seem like smart things. But then, as we start to think about the complexity requirements and especially as we start to interact with an audience like Sagewell's demographics where we're working with seniors who are perhaps less tech native, less familiar, we want to reduce the complexity there in terms of them thinking of and remembering their passwords. And so, rather than having those complexity requirements, which I think can do a good job but still make stuff harder, and how do you communicate the failure modes, et cetera, et cetera, we're switching it. And the things that we're introducing are we have increased the minimum length, so we're up to eight characters now, which is NIST's low-end recommended, so it's between 8 and 128 characters. We are capturing anytime a I forgot password reset attempt happens and the outcome of it. So we're storing those now in the database, and we're showing them to the admins. So our admin team can see if password reset attempts have happened and if they were successful. That feels like good information to keep around. Technically, we could get it from the logs, but that's deeply hidden away and only really accessible to the developers. So we're now surfacing that information because it feels like a particularly pertinent thing for us. We've introduced Rack::Attack. So we're throttling those attempts, and if someone tries to just brute force through that credential stuffing, as the terminology goes, we will lock them out so either based on IP address or the account that they're trying to log into. We also have Devise's lockable module enabled. So if someone tries to log in a bunch of times and fails, their account will go into a locked state, and then an admin can unlock it. But it gives us a little more control there. So a bunch of those are already in place. The new one, this is the one that I'm most excited about, is we're going to introduce Have I Been Pwned? And so, they have an API. We can hit it. It's a really interesting model as to how do we ask if a password has been compromised without giving them the password? And it turns out there's this fun sort of cryptographic handshake thing that happens. K-anonymity is apparently the mechanism or the underpinning technology or idea. Anyway, it's super cool; I'm excited to build it. It's going to be fun. But the idea there is rather than saying, "Don't use a password that might not be secure," it's, "Hey, we actually definitively know that your password has been cracked and is available in plaintext on the internet, so we're not going to let you use that one." STEPH: And that's part of the signup flow as to where you would catch that? CHRIS: So we're going to introduce on both signup and sign-in because a password can be compromised after a user signs up for our system. So we want to have it at any point. Obviously, we do not keep their plaintext password, so we can't do this retroactively. We can only do it at the point in time that they are either signing up or signing in because that's when we do have access to the password. We otherwise throw it away and keep only the hashed value. But we'll probably introduce it at both points. And the interesting thing is communicating this failure mode is really tricky. Like, "Hey, your password is cracked, not like here, not on our site, no, we're fine. Well, you should probably change your password. So here's what it means, there's actually this database that's called Have I Been Pwned? Don't worry; it's good, though. It's P-W-N-E-D. But that's fine." That's too many words to put on a page. I can't even say it here in a podcast. And so what we're likely to do initially is instrument it such that our admin team will get a notification and can see that a user's password has been compromised. At that point, we will reach out to them and then, using the magic of human conversation, try and actually communicate that and help them understand the ramifications, what they should do, et cetera. Longer-term, we may find a way to build up an FAQ page that describes it and then say, "Feel free to reach out if you have questions." But we want to start with the higher touch approach, so that's where we're at. STEPH: I love it. I love that you dove into how to explain this to people as well because I was just thinking, like, this is complicated, and you're going to freak people out in panic. But you want them to take action but not panic. Well, I don't know, maybe they should panic a little bit. [laughs] CHRIS: They should panic just the right amount. STEPH: Right.[laughs] So I like the starting with the more manual process of reaching out to people because then you can find out more, like, how did people react to this? What kind of questions did they ask? And then collect that data and then turn that into an FAQ page. Just, well done. CHRIS: We haven't quite done it yet. But I am very happy with the collection of ideas that we've come to here. We have a security firm that we're working with as well. And so I had my weekly meeting with them, and I was like, "Oh yeah, we also thought about passwords a bunch, and here's what we came up with." And I was very happy that they were like, "Yeah, that sounds like a good set." I was like, "Cool. All right, I feel good." I'm very happy that we're getting to do this. And there's an interesting sort of interplay between security theater and real security. And security theater, just to explain the phrase if anyone's unfamiliar with it, is things that look like security, so, you know, big green lock up in the top-left corner of the URL bar. That actually doesn't mean anything historically or now. But it really looks like it's very secure, right? Or password complexity requirements make you think, oh, this must be a very secure site. But for reasons, that actually doesn't necessarily prove that at all. And so we tried to find the balance of what are the things that obviously demonstrate our considerations around security to the user? At the end of the day, what are the things that actually will help protect our users? That's what I really care about. But occasionally, you got to play the security theater game. Every other financial institution on the internet kind of looks and feels a certain way in how they deal with passwords. And so will a user look at our seemingly laxer requirements or laxer approach to passwords and judge us for that and consider us less secure despite the fact that behind the scenes look at all the fun stuff we're doing for you? But it's an interesting question and interesting trade-off that we're going to have to spend time with. We may end up with the complexity requirements despite the fact that I would really rather we didn't. But it may be the sort of thing that there is not a good way to communicate the thought and decision-making process that led us to where we're at and the other things that we're doing. And so we're like, fine, we just got to put them in and try and do a great job and make that as usable of an experience as possible because usability is, I think, one of the things that suffers there. You didn't do one of the things on the list, or like, it's green for each of the ones that you did, but it's red for the one that you didn't. And your password and your password confirmation don't match, and you can't paste...it's very easy to make this wildly complex for users. STEPH: Security theater is a phrase that I don't think I've used, but the way you're describing it, I really like. And I have a solution for you: underneath the password where you have "We don't partake in security theater, and we don't have all the other fancy requirements that you may have seen floating around the internet and here's why," and then just drop a link to the episode. And, you know, people can come here and listen. It'll totally be great. It won't annoy anyone at all. [laughs] CHRIS: And it'll start, and they'll hear me yelling about Fn-Delete that weather.com URL. [laughter] STEPH: Okay, maybe fast forward then to the part about -- CHRIS: Drop them to the timestamp. That makes sense. Yep. Yep. STEPH: Mm-hmm. Mm-hmm. [laughs] CHRIS: I like it. I think that's what we should do, yeah. Most features on the app should have a link to a Bike Shed episode. That feels true. STEPH: Excellent Easter egg. I'm into it. But yeah, I like all the thoughtfulness that y'all have put into this because I haven't had to think about passwords in this level of detail. And then also, yeah, switching over to when things start to change and start to move away, you're right; there's still that we need to help people then become comfortable with this new way and let them know that this is just as secure if not more secure. But then there's already been that standard that has been set for your expectations, and then how do you help people along that path? So yeah, seems like y'all have a lot of really great thoughtfulness going into it. CHRIS: Well, thank you. Yeah, it's frankly been a lot of fun. I really like thinking in this space. It's a fun sort of almost hobby that happens to align very well with my profession sort of thing. Actually, oh, I have one other idea that we're not going to do, but this is something that I've had in the back of my mind for a long time. So when we use bcrypt or Devise uses bcrypt under the hood, one of the things that it configures is the cost factor, which I believe is just the number of times that the password plus the salts and whatnot is run through the bcrypt algorithm. The idea there is you want it to be computationally difficult, and so by doing it multiple times, you increase that difficulty. But what I'd love is instead of thinking of it in terms of an arbitrary cost factor which I think is 12, like, I don't know what 12 means. I want to know it, in terms of dollars, how much would it cost to, like dollars and cents, to crack a password. Because, in theory, you can distribute this across any number of EC2 instances that you spin up. The idea of cracking a password that's a very map-reducible type problem. So let's assume that you can infinitely scale up compute on-demand; how much would it cost in dollars to break this password? And I feel like there's an answer. Like, I want that number to be like a million dollars. But as EC2 costs go down over time, I want to hold that line. I want to be like, a million dollars is the line that we want to have. And so, as EC2 prices go down, we need to increase our bcrypt cost factor over time to adjust for that and maintain the million dollar per password cracking sort of high bar. That's the dream. Swapping out the cost factor is actually really difficult. I've looked into it, and you have to like double encrypt and do weird stuff. So for a bunch of reasons, I haven't done this, but I just like that idea. Let's pin this to $1 value. And then, from there, decisions naturally flow out of it. But it's so much more of a real thing. A million dollars, I know what that means; 12, I don't know what 12 means. STEPH: A million-dollar password, I like it. I feel like -- CHRIS: We named the episode. STEPH: I was going to say that's a perfect title, A Million-Dollar Password. [laughs] CHRIS: A Million-Dollar Password. But with that wonderful episode naming cap there, I think I'm done rambling about passwords. What's up in your world, Steph? STEPH: One of the things that I've been chatting with folks lately is RailsConf is coming up; it's May 17 through the 19th. And it's been sort of like that casual conversation of like, "Hey, are you going? Are you going? Who's going? It's going to be great." And as people have asked like, "Are you going?" And I'm always like, "No, I'm not going." But then I popped on to the RailsConf website today because I was just curious. I wanted to see the schedule and the talks that are being given. And I keep forgetting that there's the in-person version, but there's also the home edition. And I was like, oh, I could go, I could do this. [laughs] And I just forget that that is something that is just more common now for conferences where you can attend them virtually, and that is just really neat. So I started looking a little more closely at the talks. And I'm really excited because we have a number of thoughtboters that are giving a talk at RailsConf this year. So there's a talk being given by Fernando Perales that's called Open the Gate a Little: Strategies to Protect and Share Data. There's also a talk being given by Joël Quenneville: Your Test Suite is Making Too Many Database Calls. I'm very excited; just that one is near and dear to my heart, given the current client experiences that I'm having. And then there's another one from someone who just joined thoughtbot, Christopher "Aji" Slater, Your TDD Treasure Map. So we'll be sure to include a link to those for anyone that's curious. But it's a stellar lineup. I mean, I'm always impressed with RailsConf talks. But this one, in particular, has me very excited. Do you have any plans for RailsConf? Do you typically wait for them to come out later and then watch them, or what's your MO? CHRIS: Historically, I've tended to watch the conference recordings after the fact. I went one year. I actually met Christopher "Aji" Slater at that very RailsConf that I went to, and I believe Joël Quenneville was speaking at that one. So lots of everything old is new again. But yeah, I think I'll probably catch it after the fact in this case. I'd love to go back in person at some point because I really do like the in-person thing. I'm thrilled that there is the remote option as well. But for me personally, the hallway track and hanging out and meeting folks is a very exciting part. So that's probably the mode that I would go with in the future. But I think, for now, I'm probably just going to watch some talks as they come out. STEPH: Yeah, that's typically what I've done in the past, too, is I kind of wait for things to come out, and then I go through and make a list of the ones that I want to watch, and then, you know, I can make popcorn at home. It's delightful. I can just get cozy and have an evening of RailsConf talks. That's what normal people do on Friday nights, right? That's totally normal. [laughs] CHRIS: I mean, yeah, maybe not the popcorn part. STEPH: No popcorn? CHRIS: But not that I'm opposed to popcorn just —- STEPH: Brussels sprouts? What do you need? [laughs] CHRIS: Yeah, Brussels sprouts, that's what it is. Just sitting there eating handfuls of Brussels sprouts watching Ruby conference talks. STEPH: [laughs] CHRIS: I do love Brussels sprouts, just to throw it out there. I don't want it to be out in the ether that I don't like them. I got an air fryer, and so I can air fry Brussels sprouts. And they're delicious. I mean, I like them regardless. But that is a really fantastic way to cook them at home. So I'm a big fan. STEPH: All right, I'm moving you into the category of fancy friends, fancy friends with an air fryer. CHRIS: I wasn't already in your category of fancy friends? STEPH: [laughs] I didn't think you'd take it that way. I'm sorry to break it to you. [laughter] CHRIS: I'm actually a little hurt that I'm now in the category of fancy friends. It makes a lot of sense that I wasn't there before. So I'll just deal with...yeah, it's fine. I'm fine. STEPH: It's a weird rubric that I'm running over here. Pivoting away quickly, so I don't have to explain the categorization for fancy friends, I saw something in the Ruby Weekly Newsletter that had just come out. And it's one of those that I see surface every so often, and I feel like it's a nice reminder because I know it's something that even I tend to forget. And so I thought it'd be fun just to resurface it here. And then, we can also provide a link to the wonderful blog post that's written by Benito Serna. And it's the difference between count, length, and size and an association with ActiveRecord. So for folks that would love a refresher, so count, that's a method that's always going to perform a SQL count query. So even if the collection has already been loaded, then calling count is always going to execute a database query. So this is the one that's just like, watch out, avoid it. You're always going to hit your database when you use this one. And then next is length. And so, length loads the whole collection into memory and then returns that length to the number of items in that collection. If the collection has been loaded, then it's not going to issue a database call. And then it's just still going to use...it's going to delegate to that Ruby length method and let you know how many records are in that collection. So that one is a little bit better because then that way, if it's already loaded, at least you're not going to have a database call. And then next is the size method, which is just the one that's more highly recommended that you use because this one does have a nice safety net that is built-in because first, it's going to check if we need to perform a database call, if the records have been loaded or not. So if the collection has not been loaded, so we haven't executed a database query and stored the result, then size is going to perform a database query. Specifically, it's using that SQL count under the hood. And if the collection has been loaded, then a database call is not issued, and then going to use the Ruby length method to then return the number of records. So it just helps you prevent unnecessary database calls. And it's the reason that that one is recommended over using count, which is going to always issue a call. And then also to avoid length where you can because it's going to load the whole collection into memory, and we want to avoid that. So it was a nice refresher. I'll be sure to include a link in the show notes. But yeah, I find that I myself often forget about the difference in count and size. And so if I'm just in the console and I just want to know something, that I still reach for count. It is still a default for mine. But then, if I'm writing production code, then I will be more considered as to which one I'm using. CHRIS: I feel like this is one of those that I've struggled to lock into my head, but as you're describing it right now, I think I've got, again, another mnemonic device that we can lock on to. So I know that SQL uses the keyword count, so count that's SQL definitely. Length I know that because I use that on other stuff. And so it's size that is different and therefore special. That all seems good. Cool, locking that in my brain along with Fn-Delete. I have two things that are now firmly locked in. So you were just mentioning being in the console and working with this. And one of the things that I've noticed a lot with folks that are newer to ActiveRecord and the idea of relations and the fact that they're lazy, is that that concept is very hard to grasp when working in a console because at the console, they don't seem lazy. The minute you type out user.where some clause, and the minute you type that and hit enter in the console, Ruby is going to do its normal thing, which is like, okay, cool, I want to...I forget what it is that IRB or any of the REPLs are going to do, but it's either inspect or to_s or something like that. But it's looking for a representation that it can display in the console. And ActiveRecord relations will typically say like, "Oh, cool, you need the records now because you want to show it like an array because that's what inspect is doing under the hood." So at the console, it looks like ActiveRecord is eager and will evaluate the query the minute you type it, but that's not true. And this is a critical thing that if you can think about it in that way and the fact that ActiveRecord relations are lazy and then take advantage of it, you can chain queries, you can build them up, you can break that apart. You can compose them together. There's really magical stuff that falls out of that. But it's interesting because sort of like a Heisenberg where the minute you go to look at it in the REPL, it's like, oh, it is not lazy; it is eager. It evaluates it the minute I type the query. But that's not true; that's actually the REPL tricking you. I will often just throw a semicolon at the end of it because I'm like, I don't want to see all that noise. Just give me the relation. I want the relation, not the results of executing that query. So if you tack a semicolon at the end of the line, that tells Ruby not to print the thing, and then you're good to go from there. STEPH: That's a great pro-tip. Yeah, I've forgotten about the semicolon. And I haven't been using that in my workflow as much. So I'm so glad you mentioned that. Yeah, I'm sure that's part of the thing that's added to my confusion around this, too, or something that has just taken me a while to lock it in as to which approach I want to use for when I'm querying data or for when I need to get a particular count, or length, or size. And by using all three, I'm just confusing myself more. So I should really just stick to using size. There's also a fabulous article by Nate Berkopec that's titled Three ActiveRecord Mistakes That Slow Down Rails Apps. And he does a fabulous job of also talking about the differences of when to use size and then some of the benefits of when you might use count. The short version is that you can use count if you truly don't care about using any of those records. Like, you're not going to do anything with them. You don't need to load them, like; you truly just want to get a count. Then sure, because then you're issuing a database query, but then you're not going to then, in a view, very soon issue another database query to collect those records again. So he has some really great examples, and I'll be sure to include a link to his article as well. Speaking of Ruby tidbits and kind of how this particular article about count, length, and size came across my view earlier today, Ruby Weekly is a wonderful newsletter. And I feel like I don't know if I've given them a shout-out. They do a wonderful job. So if you haven't yet checked out Ruby Weekly, I highly recommend it. There are just always really great, interesting articles either about stuff that's a little bit more like cutting edge or things that are being released with newer versions, or they might be just really helpful tips around something that someone learned, like the difference between count, length, and size, and I really enjoy it. So I'll also be sure to include a link in the show notes for anyone that wants to check that out. They also do something that I really appreciate where when you go to their website, you have the option to subscribe, but I am terrible about subscribing to stuff. So you can still click and check out the latest issue, which I really appreciate because then, that way, I don't feel obligated to subscribe, but I can still see the content. CHRIS: Oh yeah. Ruby Weekly is fantastic. In fact, I think Peter Cooper is the person behind it, or Cooperpress as the company goes. And there is a whole slew of newsletters that they produce. So there's JavaScript Weekly, there's Ruby Weekly, there's Node Weekly, Golang Weekly, React Status, Postgres Weekly. There's a whole bunch of them. They're all equally fantastic, the same level of curation and intentional content and all those wonderful things. So I'm a big fan. I'm subscribed to a handful of them. And just because I can't go an episode without mentioning inbox zero, if you are the sort of person that likes to defend the pristine nature of your email inbox, I highly recommend Feedbin and their ability to set up a special email address that you can use to then turn it into an RSS feed because that's magical. Actually, these ones might already have an RSS feed under the hood. But yeah, RSS is still alive. It's still out there. I love it. It's great. And that ends my thoughts on that matter. STEPH: I have what I feel is a developer confession. I don't think I really appreciate RSS feeds. I know they're out there in the ether, and people love them. And I just have no emotion, no opinion attached to them. So one day, I think I need to enjoy the enrichment that is RSS feeds, or maybe I'll hate it. Who knows? I'm reserving judgment. Either way, I don't think I will. [laughs] But I don't want to box future Stephanie in. CHRIS: Gotta maintain that freedom. STEPH: On that note, shall we wrap up? CHRIS: Let's wrap up. The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeee!!!!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

The Bike Shed
335: Start Messy

The Bike Shed

Play Episode Listen Later Apr 26, 2022 35:38


Steph has a question for Chris: When you have no idea how you're going to implement a feature, how do you write your first test? Chris has thoughts about hybrid teams (remote/in-person) and masked inputs. This episode is brought to you by ScoutAPM (https://scoutapm.com/bikeshed). Give Scout a try for free today and Scout will donate $5 to the open source project of your choice when you deploy. Preemptive Pluralization is (Probably) Not Evil (https://www.swyx.io/preemptive-pluralization) iMask (https://imask.js.org/) Mitch Hedberg - Escalator Joke (https://www.youtube.com/watch?v=yHopAo_Ohy0) This episode is brought to you by Studio 3T (https://studio3t.com/free). Try Studio 3T's full suite of features for 30 days, no payment details needed. Become a Sponsor (https://thoughtbot.com/sponsorship) of The Bike Shed! Transcript: STEPH: I am recording in a new room because we're in Pennsylvania, and so I'm recording at this little vanity desk which is something. [laughs] But there's a mirror right in front of me, so I feel very vain because it's just like, [laughs] I'm just looking at myself while I'm recording with you. It's something. CHRIS: [laughs] That is something. STEPH: [laughs] So, you know. CHRIS: Fun times. STEPH: Pro podcast tip, you know, just stare at yourself while you chat, while you record. CHRIS: I mean, if that works for you, you know, plenty of people in the gym have the mirrors up, so podcasting is like exercising in a way, and I think it makes sense. STEPH: I appreciate the generosity. [laughs] CHRIS: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Chris Toomey. STEPH: And I'm Steph Viccari. CHRIS: And together, we're here to share a bit of what we've learned along the way. So, Steph, what's new in your world? STEPH: Hey, Chris. So I have a funny/emotional story that [laughs] I'm going to share with you first because I feel like it kind of encapsulates how life is going at the moment. So we've officially moved from South Carolina to North Carolina. I feel like I've been talking about that for several episodes now. But this is it: we have finally vacated all of our stuff out of South Carolina house and relocated to North Carolina. And once we got to North Carolina, we immediately had to then leave town for a couple of days. And normally, Utah, our dog, stays with an individual in South Carolina, someone that we found, trust, and love. And he has a great time, and I just know he's happy. But we didn't have that this time. So I had to find just a boarding facility that had really high reviews that I felt like I could trust him with. I didn't even have time to take him for a day to test it out. It was one of those like, I got to show up and just drop him off and hope this goes well, so I did. And everything looks wonderful. Like, the facility is very clean. I had a list of things to look for to make sure it was a good place. But it's the first time leaving him somewhere where he's going to spend significant time in a kennel that has indoor-outdoor access. And as I walked away from him, I started to cry. And I just thought, oh no, this is embarrassing. I'm that dog mom who's going to start crying in this boarding facility as she's leaving her dog for the first time. So I put on my shades, and I managed to make it through the checkout process. But then I went to my truck and just sat there and cried for 15 minutes and called my husband and was like, "I'm doing the right thing, right? Like, tell me this is okay because I'm having a moment." And I finally got through that moment. But then I even called you because you and I were scheduled to chat. And I was like, I am not in a place that I can chat right now. I think I told you when you answered the phone. I was like, "Everything is fine, but I sound like the world's ending, or I sound like a mess." [laughs] And yeah, so I had like two hours of where I just couldn't stop crying. I partially blame pregnancy hormones. I'm going to go with that as my escape rope for now. So I feel like that's been life lately. Life's been a little overwhelming, and that felt like the cherry on top. And that was the moment that I broke. Update: he's doing great. I've gotten pictures of Utah. He's having a wonderful time at camp, it seems. [laughs] It was just me, his mom, who is having trouble. CHRIS: Well, you know, reasonable to worry, and life's dialed up to 11 and all of that. But yeah, I will say even though you lead the conversation with everything's fine, your tone of voice did not imply that everything was fine. So when I eventually came to understand what we were talking about, I hope I was kind in the moment. But I was like, oh, okay, this is fine. We're fine. I'm so sorry you're feeling terrible right now. STEPH: [laughs] CHRIS: But okay, we're fine. For me, there was a palpable moment of like, okay, my stress is now back down a little bit. But I'm glad that things are going well and that Utah is having a fun vacation. STEPH: Yep, he seems to be doing fine. I've calmed down. You know, as you said, life's been dialed up lately. On a less emotional note and something that's a little bit more technical, I had a really great conversation with another thoughtboter where we were talking about testing. And the idea of when you learn testing, it's often very focused on like, you have this object, and it has a method. And so, you're going to write a unit test for this particular method. And it's very isolated, very specific as to the thing that you're looking to test. Versus in reality, when you pick up tickets, you don't have that scope, and like, it is so broad. You have to figure out what feature you're implementing, figure out how to test it. And it feels like this mismatch between how a lot of people learn to test and learn TDD versus then how we actually practice it in the wild. And so we had a phone conversation around when you are presented with a ticket like that, and you have no idea how you're going to implement a feature, how do you get started with testing, and when do you write your first test? Do you TDD? Do you BDD? Or do you PDD? That last one I made up, it stands for Panic-driven development. But it's what's your approach to how do you actually then get to the point where you can write a test? And I have a couple of thoughts. But I'm really curious, how does that flow work for you? What have you learned throughout the years to then help yourself write that first test? Or where do you start? CHRIS: Well, this is an interesting question. I like this one. I think it varies. And I think there's a lot of dogma around TDD as a practice. And I think it is super useful to break that apart and hear different individual stories of it. I know there are plenty of folks who are like, TDD is just not a thing and whatnot, and I'm certainly not in that camp. But I also don't TDD 100% of the time because sometimes I'm not super clear on what I'm doing, or I'm in more of an exploratory phase. That said, I think there's a...I want to answer the question somewhat indirectly, which is I know how to test most of the code that I work on now as a web developer in a Rails application because I've done most of the things a bunch of times. And the specifics may be different, but the like, to integrate with this external system, and I have to build an API client or whatever, I know how to do that. And there is a public API of some class that I will be exercising against and so I can write tests against that. Or I know that the user is going to click a button, and then something needs to happen. And so I can write that test, and it fails, and then it starts to push me towards the implementation. There are also times where it's actually quite hard to get the test to lead you in the right direction, and you have to know what hop to make, and so sometimes I just do that. But yeah, rolling back a little bit, I think there is a certain amount of experience that is necessary. And I think one of the critical things that I want to share with folks that are potentially newer to testing overall is that it is actually quite hard. You have to understand your system and how you're going to approach it, you know, one step removed, or it's like a game of chess where you're thinking a couple of moves ahead. You have to understand it in a deeper way. And so, if testing is difficult, that might just be totally reasonable at this point. And as you come to see the patterns within a Rails application or whatever type of application you're working on over and over, it becomes easier to test. But if testing is hard, that may not mean...like, how do I phrase this? There's like an impostor syndrome story in here of like, if you're struggling with testing, it may not be that something is fundamentally broken. You just may need a couple more chances to see that sort of thing play out. And so, for me, in most cases, I tend to know where to start or when not to. Like, I feel fine not testing when I don't test most of the time. I will eventually get things under test coverage such that I feel confident in that. And whenever I have one of those moments, I will stop and look at it and say, "Why didn't I know how to test this from the front, like, from the start?" But it's rare at this point for things to be truly exploratory. There's always some outer layer that I can wrap around. But like, I know X needs to happen when Y occurs. So how do I instrument the system in that way? But yeah, those are some thoughts. What are your thoughts? Does what I said sound reasonable here? STEPH: Yeah, I really like how you highlighted that pausing for reflection. That was something that I didn't initially think of, but I really liked that, to then go back to be like, okay, revisiting myself a couple of days or however earlier when I first started this. Now I can see where I've ended up. How could I have made that connection sooner as to where I was versus the tests I ended up with? Or perhaps recognizing that I couldn't have gotten there sooner, that I needed that journey to help me get there. So I really like the idea of pausing for reflection because then it helps cement any of those learnings that you have made during that time. Also, the other part where you mentioned the user clicks a button, and something happens, that's where I immediately went with this. I also liked that you highlighted that TDD has that bit of dogma, and I don't always TDD. I do what I can, and it helps me. But it has to be a tool versus something that I just do 100% of the time. But with more of that BDD approach or that very high-level user-level integration test of where if I need to pull data from an API and then show it to the user, okay, I know I can at least start with a high-level test of I want the user to then see some data on a page. And that will lead me down some path of errors. It might help me implement a route and a controller and then a show action, so it will at least help me get started. Or even if it doesn't give me helpful enough errors, it at least serves as my guideline of like, this is my North Star. This is where I'm headed. So then, if I need to revisit, okay, what's the thing that I'm focused on at the moment? I can go back and be like, okay, I'm focused on achieving this. What's the next smallest step I can take to get there? The other thing that I've learned over time is I've given myself the chance to be messy because I got so excited about the idea of unit testing and writing small, fast test that I would often try to start with small objects and then work my way backwards into like, okay, I have this one object that does this thing and one object that like...let's use a concrete example. So one object that knows how to communicate with API and one object that knows how to then parse and format the data I want and then something else that's then going to present that data to the user. But I found when I started with small objects, I would get a little lost, and I wasn't always great at bringing them together. So I've taken the opposite approach of where if I'm really not sure where I'm headed and I'm in that more exploratory phase or even just that first initial parse of a feature, I will just start messy. So if I am pulling data from an API and need to show it to a user on a screen, I'll just dump it in the controller if I need to. I'll put it all there together. And then once I actually have something that is parsing, or I have something appearing on the page, then I will start to say, "Okay, now that I can see what I need and I can see the pieces that I've written, how can I then start to extract this into smaller objects?” And now, I can start writing unit tests for that data. So that is something that has helped me is just start high, keep it high, be messy, and until you start to see some of the smaller objects that you can pull out. CHRIS: Yeah, I think there's something that you were just saying there that clicked for me of we didn't start with the why of TDD. And I don't think we've talked about why we believe in TDD in a while. So this feels like a thing we're saying. It's not good just because it's good, or we don't believe it's good just because that's what we say. For me, it is because it anchors us outside of the code sort of it starts to think of it from the user perspective or some outer layer. So even if you're unit testing some deeply nested class within your application, there's still an outer layer. There's still a user of that class. And so, thinking about the public API, I think is really useful. And then the further out you get, the better that is, and I believe strongly in thinking from the outside in on these sort of things. And then the other thing you said of allowing for refactoring. And if we have tests, then it's so much easier to sort of...I totally 100% agree with like; I start messy. I start very messy. I wanted to pretend that I was going to be like, oh, I'm so...Steph, I can't believe this. But no, of course, I start messy. Why would you start trying to do the hard thing first? No, get something that works. But then having the test coverage around that makes it so much easier to go through those sequential refactoring steps. Versus if you have to write the code correctly upfront and then add test coverage around that, it sort of inverts that whole thing. And so, although it may take a little bit longer to write the tests upfront, I do exactly what you're describing of like, I write the tests that tell some truth about the system and constrain the system to do that thing. And then I can have a messy implementation that I can iteratively refactor over and over, and I can extract things from. And then, I can tell a more concise testing story about those. And so it really is both the higher-level perspective I think is super useful and then the ability to refactor under that test coverage is also very useful. And it makes my job easier because I can start messy. I love starting messy. It's so much better. STEPH: Yeah, and I think former me had the idea that for me to do TDD properly meant that I had these small, encapsulated objects that I wrote unit tests for. And yes, that is the goal. I do want that, but that doesn't mean I have to start there. That is something that then I can work my way towards. That also falls in line with the adage from Sandi Metz that the wrong abstraction is more costly than no abstraction. And so I'd rather start with no abstractions and then start to consider, okay, how can I actually move this out into smaller objects and then test it from there? There's also something that I heard that I haven't done as often, but I really liked the idea; it feels very freeing, is that when you do get started and if you write your first test, if you write a test and it helps you make some progress but then you come back to it later and you're like, you know, the test doesn't really add value, or it's not helping me anymore, just thank it and delete it and move on. Just because you wrote it doesn't mean it needs to stay. So if it provided some benefit to you and helped you through that journey of adding the feature, then that's wonderful. But don't be timid about deleting it or changing it so that it does serve you because otherwise, it's just going to be this toxic test that gets merged into the main branch, and it's going to be untrustworthy. Or maybe it's fussy and hard to please, or it's just really not the supportive test that you're looking for. And so then you can turn it into more of a supportive test and make it fit your goals instead of just clinging to every test that we've written. CHRIS: I like the framing of tests as scaffolding to help you build up the structure. But then, at the end, some of the scaffolding gets ripped away and thrown out. And I do think, again, testing ends up in this weird place. The dogmatic thing that we were talking about earlier feels very true. And I've noticed, particularly on larger teams, folks being very hesitant to delete tests like, that feels like sacrilege. Of course, you can't delete tests; the tests are how we know it's true, which is true, but you can interrogate that. You can see like, how true is it? And every test has a cost and maintenance burden, runtime, et cetera. You probably know well, Steph, about having test suites that take a bunch of time to run and then maybe wanting to spend a little bit of time trying to reduce that overall time. And so there's always going to be a trade-off there. Actually, someone reminded me of an anecdote recently. I joined a project, and most of the test suite or all of the test suite was commented out because it was flaky or intermittent. And I was like, "Oh, I'm going to delete that." And people were like, "You're what?" I'm like; it's commented out. We're not using it. Let's tell the truth. Git will have it. We can go back and get it. But let's tell the truth with what we're like...this commented-out test suite is almost worse in my mind than having nothing there. The nothing feels painful, right? Let's experience that. Whereas the commented out stuff is like, well, we have a test suite; it's just commented out. It's like, no, you don't have a test suite at all. That's not what's going on here. But there were other thoughtboters on the project that poked a good amount of fun at me when they were like, "The first thing you did on this project was delete the test suite?" As I was like, "Yeah, I don't know, I was feeling spicy that day or something." But I think the test suite needs to serve the work that we're doing in the same way that everything else does. And so occasionally, yeah, deleting tests is absolutely the right thing and then probably add back some more. STEPH: It's funny how that reaction exists. And I've done it before myself where like, if you see commented out code and you put up a PR to remove it, I feel like most people are going to be like, yeah, yeah, that's great. Let's get rid of this. It's clearly not news. It's commented out. But then removing a skipped test then has people like, "Well, but that test looks like it could be valuable, and we're going to fix it." And it's like...all I can go back to is that silly example of like, you've got your skinny jeans, one day I'm going to fit into those skinny jeans. And so one day, I'm going to fix this test, and it's going to serve the purpose. And it's going to be the me I want to be. [laughs] And it is funny how we do that. With code, we're like, sure, we can get rid of it. But with tests, we feel this clinginess to them where we want to hold on to it and make it pass. And I think that sometimes has to do with the descriptions. There are test descriptions commented out that I've seen are like, user can log in, or if given a user without permission, they can't access. And it's like, oh, that sounds important. I'm now nervous to delete you versus fix you, but you're still not actually running and providing value. And so then I have to negotiate with myself as to where do we actually go from here? But I do love the idea of deleting tests that are skipped because we should just let them go. We either have to dedicate time to fix them or let them go and make that hard decision. CHRIS: The critical idea of future me will have more time, future me will be calm and will work through all the other bugs and future discounting; as far as I understand it as a formalization of the term, yeah, it's never true. I've only gotten busier over time, just broadly speaking. And that seems to be a truism in software projects as well. It's like, oh, we just have to write a bunch of features, and then it'll be calm. I don't even think I'd want that. But future me will not have more time. And so choosing the things that we do invest in versus not is tricky, but the idea of that future me will have a lot of time or future us probably not true. STEPH: Well, I think the story that I just shared at the beginning of our chat highlights that future me won't always be calm. [laughs] So let's work with what I've got. Let's not bank on that. Future Stephanie might be very emotional about dropping her dog off at boarding for a couple of days. [laughs] Future me might be very emotional about fixing this test. All right, well, thanks for going on that journey with me. That's really helpful. I knew you'd have some great insights there. Mid-roll Ad: Hi, friends, and now a quick break to hear from today's sponsor, Scout APM. Scout APM is an application performance monitoring tool that's designed to help developers find and fix performance issues quickly. With an intuitive user interface, Scout will tie bottlenecks to source code so you can quickly pinpoint and resolve performance abnormalities like N+1 queries, slow database queries, and memory bloat. Scout also recently implemented external service monitoring, adding even more granularity when it comes to HTTP requests and API calls. So give Scout a try today with a free 14-day trial and experience first-hand why developers worldwide call Scout their best friend. And as an added bonus for Bike Shed listeners, Scout will donate $5 to the open-source project of your choice when you deploy. To learn more, visit scoutapm.com/bikeshed. That's scoutapm.com/bikeshed. CHRIS: What's going on in my world? Last week we had our first ever Sagewell all-hands get-together in person. Many of us have met in person before, but not everyone. And so this was a combination celebration for our seed fundraising round, which had happened actually sometime right at the end of last year. But due to COVID in the world and complexity, it was difficult to get everybody together. So that finally happened. And then we sort of grafted on to that celebration, that party that we were having. Like, let's just extend a day in either direction and do some in-person working and all of that. And that was really great. I'm trying to find that ideal middle ground between we are a remote team, but there is definitely value in occasionally being in person, particularly getting to know people but also just having some higher bandwidth conversations, planning, things like that. They just feel different in person. And so, how do we balance that? And how do we be most productive and all that? But it was really great to meet the team more so than I had on the internet and get to spend some time in person and do some whiteboarding. I drew on a whiteboard with a team. We were all looking at the same whiteboard. We're in the same room. And I drew on a whiteboard some entity relationship diagrams. It was awesome. [laughs] It was super fun. It was one of those cases where we had built an assumption deeply into our codebase, and suddenly instead of having one of a thing, we may now have multiple of a thing. There's a wonderful blog post by Shawn Wang called Preemptive Pluralization which I think is based on an episode of Ben Orenstein's podcast, The Art of Product, where Ben basically framed the idea of like, I've never regretted pluralizing something earlier. A user has one account; they have multiple accounts. They just happen to have one at this time, et cetera. So we're in one of those. And it was a great thing to be able to be in a room and whiteboard. I knew at the time when I did it way back when that I was making the wrong decision. But I didn't know exactly how and the shape. And so now we have to do that fun refactoring so glad that we have a giant test suite that will help us with said refactoring. But yeah, so that was really great to be able to do in person. STEPH: I think there can be so much value in getting together and getting to see your team and, like you said, have those high-level conversations and then just also getting to hang out. So it's really nice to hear that reinforced since you experienced that same positivity from that experience. Do you think that's something that y'all will have going forward? Do you think you're going to try to get together like once a year, once a quarter? Maybe it hasn't even been talked about. But I'm hearing that it was great and that maybe there will be some repeats. CHRIS: Yes, yeah. I think I'm inclined to quarterly at a minimum and maybe even slightly more than that. Some of us are centered around Boston, and so it's a little bit easier for us to pop in and work at a WeWork, that sort of thing. But I think broadly, getting the team together and having that be intentional. And personally, I'm inclined to that being more social time than productive time because I think that's the thing that is most useful in person is building relationship and rapport and understanding folks better. I remember so pointedly when thoughtbot would have the annual Summer Summit, and leading up to that; there was a certain amount of conversation. But there were also location-specific rooms, and a lot of the conversation happened like in the Boston channel or whatnot. And then, without fail, every year after the Summer Summit, suddenly, there was a spike in cross-team chatter. Like, the Ruby room now had a bunch of people from San Francisco talking to Boston, talking to New York, et cetera. And it was just this incredibly clear...I think we could actually, like, I think at one point someone plotted the data, and there's just this stepwise jump that would happen every time. And so that sort of connecting folks is really what I believe in there. And the more we're leaning into the remote thing, then the more I think this is important. So I think quarterly is probably the lowest end that I would think of, but it might be more. And it's also a question of like, what shape does this take? Is it just us going and hanging out somewhere? Or are we productively trying to get together with a whiteboard? I think we'll figure that out as we go on. But it's definitely something that I'm glad we've done now, set the precedent for, and we'll hopefully do more of moving on. STEPH: Yeah, I always really love the thoughtbot Summits. In fact, we have one coming up. It's coming up in May, and this one's taking place in UK. But there have been some interesting conversations around Summit because before, it was the idea that everybody traveled. But typically, they were in Boston, so for me, it was particularly easy because it was already where I lived. So then showing up for Summit was no biggie. But with this one happening in UK and COVID and travel still being a concern, there's been more conversations around; okay, this is awesome. People who want to get together can. There are these events going on. But there are people who don't want to travel, don't feel up to travel. They have family obligations that then make it very difficult for them to leave one partner at home with the kids. And I myself I'm in that space where I thought really hard about whether I was going to travel or not. And I've decided not to just for personal reasons. But then it brings up the question of okay, well, if we have a number of people that are going to be in person together, then what about the people who are remote? And the idea of running something that's hybrid is not something that we've really figured out. But those that are remote, we're going to get together and figure out what we want to do and maybe what's our version of our remote summit since we're not going to be traveling. But I feel like that's definitely a direction that needs to be considered as teams are getting in person because if you do have people that can't make it, how can you still bring them in so it's an inclusive event but respect to the fact that they can't necessarily travel? I don't know if that's a concern that every team needs to have, but it's one that I've been thinking about with our team. And then I know others at thoughtbot we've been considering just because we do have such a disparate team. And we want to make everybody comfortable and feel included. CHRIS: Yeah, as with everything in this world, there's always complexities and subtlety. Thankfully, for our first get-together, we were able to get everyone into the same space. But I do wonder, especially as the team grows, even just scheduling, the logistics of it become really complicated. So then does the engineering team have get-togethers that are slightly different, and then there's like once yearly a big get-together of the whole team? Or how do you manage that and dealing with family situations and all that? It is very much a complicated thing that thankfully was very straightforward for us this first time, but I fully expect that we'll have to be all the more intentional with it moving forward. And, you know, that's just the game. But switching gears ever so slightly, we did have a fun thing that we've worked on a little bit over the past few weeks. We've finally landed it in the app. But we were swapping out our masked input library that we were using, so this is for someone entering their birthday, or a phone number, or social security number, or dates. I guess I already said dates. Passwords I think we also use here. But we have a bunch of different inputs in the app that behave specially. And my goodness, is this one of those things that falls into the category of, oh yeah, I assume this is a solved problem, right? We just have a library out there that does it. And each library is like, oh no, all of the other libraries are bad. I will come along, and I will write the one library to solve all of the problems, and then we'll be good. And it is just such a surprisingly complicated space. It feels like it should be more straightforward. And as I think about it, it's not; it's dealing with imperative interactions between a user and this input. And you need to transform it from what happens when you hit the delete key? What do you want to happen? What's the most discoverable for every user? How do we make sure they're accessible? But my goodness, was it complicated. I think we're happy with where we landed, but it was an adventure. STEPH: I'll be honest, that's something that I haven't given as much thought to. But I guess that's also I just haven't worked with that lately in terms of a particular library that then masks those inputs. So I'm curious, which library were using before, and then which one did you switch to? CHRIS: That's a critical piece of information that I have left off here. So for the previous one, we were using one called svelte-input-mask, which, again, part of the fun here is you want to have bindings into whatever framework that you're using. So svelte-input-mask is what we were using before. We have now moved on to using iMask, which is not like the thing you wear on your face, but it is the letter I so like igloo, Mike, et cetera, I-M-A-S-K, iMask. And so that is a lower-level library. There are bindings to other things. But for TypeScript and other reasons, we ended up implementing our own bindings in Svelte, which was actually relatively straightforward. Again, big fan of Svelte; it's a wonderful little framework. But that is what we're using now, and it is excellent. It's got a lot of features. We ended up using it in a slightly more simple version or implementation. It's got a lot of bells and whistles and configurations. We went up the middle with it. But yeah, we're on iMask, which also led to a very entertaining moment where it was interacting with our test suite in an interesting way. And so, one of the developers on the team searched for Capybara iMask. [laughs] And I forget exactly how it happened, but if you Google search that, for some reason, the internet thinks an iMask is a thing that goes over your mouth. And so it's a Capybara, like the animal, facemask. It's very confusing, but this got dropped into our Slack at one point, someone being like, "I searched for Capybara iMask, and it got weird, everybody." So yeah, that was a fun, little side quest that we got to go on. STEPH: [laughs] I just Googled it as you told me to, and it's adorable. Yeah, it's a face mask, and it has a little capybara cartoon on the front of it. Yeah, there are many of these. [laughs] CHRIS: When I think of an iMask, though, it's the thing that you put over your eyes to block the light if you want to sleep. But they're like, an iMask like, a mask that still keeps her eyes outside of it. I don't understand the internet. It's a weird place. STEPH: I think that was just Google saying Capybara iMask. Nope, don't know I, so let's put together Capybara mask, and that's what you got back. [laughs] CHRIS: I guess, yeah. It's just a Capybara mask. And I'm projecting the ‘I' because I phonetically heard that for a while. Anyway, yes. But yeah, masked inputs so complicated. STEPH: This is adorable. I feel like there should be swag for when people move. Like when people find things like this, this is the type of thing that then I stash and then wait for their anniversary at the company, and then I send it to them to remind them of this time that we had together. [laughs] There was also a moment where you said, ‘I.' You were explaining I as in in the letter I, not E-Y-E for eyemask. And you said igloo, and my brain definitely short-circuited for a minute to be like, did he just say igloo? Why did he say igloo? And it took me a minute to, oh, he's helping phonetically say that this is for the letter I. CHRIS: Yep. The NATO phonetic alphabet that if you don't explain that that's what you're doing, now I'm just naming random other objects in the world. Sorry. STEPH: [laughs] CHRIS: And that's why I cut myself off halfway through. I'm like, now you're just naming stuff. This isn't helping. STEPH: [laughs] CHRIS: Yes, the letter I, the letter M. [laughs] STEPH: All of that was a delightful journey for me, and I was curious. I'm glad you brought the test because I was curious if y'all are testing if things are getting obscured, but it sounds like y'all are, which is what helped give you confidence as you were switching over to the new library. CHRIS: Yeah, although to name it, we're not testing at a terribly low level. This is a great example of where I believe in feature specs. Like, within our Capybara feature spec, we are saying, and then as a user, I type in this value into the input. And critically, although this input needs to have special formatting and presentational behavior, it should functionally be identical. And so it was a very good litmus test of does this just work? And then, actually, our feature specs ended up in a race condition, which is just an annoying situation where Capybara moves so quickly that it represented a user. But as we were having that conversation, I was like, wait a minute; I know that users are slower than a computer. But is this actually an edge case that's real that we need to think about? And I think we did end up slightly changing our implementation. So our feature specs did, in a way, highlight that. But mostly, our feature specs did not need to change to adapt to and then fill in the formatted input. It was just fill in the input with the value. And that did not change at all, but it did put a tiny bit of pressure on our implementation to say, oh, there is a weird, tiny, little race condition here. Let's fix that. And so we did race conditions, no fun at all. STEPH: Interesting. Okay, so y'all aren't actually testing. Like, there's no test that says, "Hey, that when someone types into this field, that then there should be this different UI that's present because then we are obscuring the text that they're putting into this field." It was, as you mentioned, we're just testing that we changed over libraries, and everything still works. So then do you just go through that manual test of, then you go to staging, and then you test it that way? CHRIS: Yeah, that's a great question, yes, although as you say it, it's interesting. I guess there's a failure mode here or that our test suite does not enforce that the formatting masking behavior is happening. But it does test that the value goes through this input, gets submitted to the server, turns into the right type of value in the back end, all of that. And so I guess this is an example of how I think about testing, like, that's the critical bit, and then it's a nicety. It's an enhancement that we have this masking behavior. But if that broke, as long as the actual flow of data is still working, that can't break in a way that a user can't use. It sort of reminds me of the Mitch Hedberg joke, an escalator can never break, and it can only become stairs. And so I'm in that mindset here where a masked input that you have proper feature spec coverage around can never quote, unquote, "break." It can just become a plain text input. STEPH: I love how much that resonates with me. And I now know that when I'm writing tests, I'm going to think back to Mitch Hedberg and be like, oh, but is it broken-broken, or is it just now stairs? Because that's often how I will think of feature specs and how low level I will get with them. And this is on that boundary of like, yes, it's important that we want to obscure that data that someone's typing in, but it's not broken if it's not obscured. So there's that balance of I don't really want to test it. Someone will alert us. Like if that breaks, someone will alert us, and it's not the end of the world. It's just unfortunate. But if they can't sign in or they can't actually submit the form, that's a big problem. So yes, I love this comparison now of is it actually broken, or is it just stairs? [laughs] As a guideline for, how much should we test at this feature level or test in general? What should we care about? CHRIS: I feel like this is a deep truth that I believed for a long time. And I think I probably, somewhere in the back of my head, connected it to this joke. But I feel really good that I formally made that connection now because I feel like it helps me categorize this whole thing. Sorry for the convenience as a joke. And so yeah, that's where we're at. STEPH: For anyone that's not familiar with the comedian Mitch Hedberg, we'll be sure to include a link to that particular joke because it's delightful. And now it's connected to tech, which makes it just even more delightful. CHRIS: I only understand anything by analogy, especially humorous analogy. So this is just critical to my progression as a developer and technologist. STEPH: Yeah, I've learned over the years that there are two ways that I retain knowledge: it either caused me pain, or it made me laugh. Otherwise, it's mundane, and it gets filtered out. Laughter is, of course, my favorite. I mean, pain sticks with me as well. But if it's something that made me laugh, I just know I'm far more likely to retain it, and it's going to stick with me. Mid-Roll AD: And now a quick break to hear from today's sponsor, Studio 3T. When you're developing applications, it can often be a chore to work with your underlying data. Studio 3T equips you with a complete set of tools to work with MongoDB data. From building queries with drag and drop, to creating complex aggregation pipelines, Studio 3T makes it easy. And now, there's Studio 3T Free, a free edition of Studio 3T, which delivers an essential core of tools. This means you can get started, for free, with Studio 3T Free, and when you're ready, you can upgrade and enjoy even more features through Studio 3T Pro and Studio 3T Ultimate. The different editions unlock more tools and additional integrations with MongoDB, SQL, Oracle, and Sybase. You can start today by downloading Studio 3T Free, which also includes a 30-day free trial of all the features of Studio 3T Ultimate, so you can try out some of the enterprise features as well. No credit card required. To start your trial, head to studio3t.com/free. That's studio3t.com/free. CHRIS: On that wonderful framing there, I think we should wrap up. What do you think? STEPH: Let's wrap up. CHRIS: The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeee!!!!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

Closing Bell
Closing Bell Overtime: Snap Earnings, Market "Reality Check" 4/21/22

Closing Bell

Play Episode Listen Later Apr 21, 2022 44:05


Snap Inc. shares are volatile in after-hours trade after the company missed earnings expectations. Stephanie Link from Hightower gives her instant reaction and analysis to the report. Plus, Avery Sheffield from VantagePoint says that high-flying growth names are in for a "reality check." She takes a closer look at market valuations. And, is it time to get cautious? Chris Toomey from Morgan Stanley Private Wealth Management outlines his strategy.

The Bike Shed
334: Name That Bike

The Bike Shed

Play Episode Listen Later Apr 19, 2022 42:24


Chris got a bike. Specifically, he bought a bike to use in a triathlon he signed up to participate in. Now he needs to name the bike, and speaking of naming things, a more technical topic that he talks about is the Crispy Brussels Snack Hour. Steph talks about Rescue Rails projects and increasing developer acceleration. They answer a listener question asking, "Why do so many developers and agencies, thoughtbot included, replace the default test suite in Rails with RSpec?" This episode is brought to you by ScoutAPM (https://scoutapm.com/bikeshed). Give Scout a try for free today and Scout will donate $5 to the open source project of your choice when you deploy. Translate frustrations into professional corporate (https://twitter.com/MeanestTA/status/1509936432625897474) Learn Hotwire by Building a Forum (https://twitter.com/afomera/status/1512287468078264322) parallel_tests (https://github.com/grosser/parallel_tests) parallelsplittest (https://github.com/grosser/parallel_split_test) This episode is brought to you by Studio 3T (https://studio3t.com/free). Try Studio 3T's full suite of features for 30 days, no payment details needed. Become a Sponsor (https://thoughtbot.com/sponsorship) of The Bike Shed! Transcript: STEPH: Oh, but I recently learned that Robert Downey Jr. in the Marvel movies he's snacking a lot, maybe not Iron Man, but something...oh no, he's stacking a lot. And I'd read that he was snacking a lot on set, and so they just built it in to where like, sure, you can snack as your character while you're doing stuff. CHRIS: [laughs] STEPH: And I think that's so cool because I find that I am eating every time I show up to record with you. So I would like the same special star treatment as Robert Downey Jr., [laughs] and I just get to eat during each Bike Shed. [laughs] CHRIS: All right. [chuckles] My understanding is also that he was wildly the highest paid of all the actors, so I think that should also come along with this. STEPH: [laughs] CHRIS: Yeah, there's a lot that we can sort of layer on here, but it makes sense to me, and I'm fully on board. STEPH: You're an excellent agent. Thank you for fighting for my higher pay. [laughter] CHRIS: You are welcome. STEPH: What a good co-host you are. Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Steph Viccari. CHRIS: And I'm Chris Toomey. STEPH: And together, we're here to share a bit of what we've learned along the way. One of these days, I'm going to say, "I'm Chris Toomey," and then I'm just going to see how you roll with it, although now I'm ruining it, I should have just gone for it. [laughs] CHRIS: Nothing can prepare me for this despite the fact that you're telling me in this moment. In that future moment when you do it, I will still be completely knocked out of whack. Just like for anyone out there listening, the thing that Steph would normally have said instead of what [laughs] she just said was, "What's new in your world?" STEPH: [laughs] CHRIS: And I contractually require that that is the only way she starts this question to me because I get completely lost. She's like, "How are you doing?" I just overthink it, and I get lost, and then we end up in a place like this where I'm just rambling. STEPH: Every podcast contract you have from here on out must begin with hey, Chris, what's new in your world? [laughs] I will still get to that question. I just also had to tell you my future joke. I'm going to play that. Hopefully, you'll forget, and one day I will resurface. CHRIS: I can pretty much promise you that I'm going to forget it. [laughter] STEPH: Excellent. Well, to make sure I stick within the Chris Toomey contract guidelines, hey, Chris, what's new in your world? CHRIS: What's new in my world? Now I just want to spend a lot of time putting together my rider. There can be no brown M&M's in the bowl. No eye contact, please. And I can only be addressed with this one question which is, to be clear, very not true, Steph. And I always record with a video because we actually like to have human faces attached to things. Anyway, I'm going to tighten this all up. When we get to the technical segment of my world, I'm going to tell you about Crispy Brussels Snack Hour, so just throwing that out there as an idea. But before we do that, I'm going to share a fun little thing which is I bought a bike, which is exciting. It's not that exciting. People have bikes. This is exciting for me. But the associated thing that is more exciting/a little terrifying is I'm going to try and run a triathlon. I'm going to try and run, swim, and bike a triathlon as they go, specifically a sprint triathlon for anyone out there that's listening and thinking, oh wow, that sounds like a thing. The sprint is the shortest of the distances, so that's what I'm going to go for. But yeah, that's a thing that I'm thinking about in my world now. STEPH: I know next to nothing about triathlons. So what is a sprint in terms of like, what is the shortest? What does that mean? CHRIS: I think there actually maybe even shorter distances but of the common, there's sprint, Olympic. I want to say half Ironman, and then Ironman are the sequence. And an Ironman, as far as I understand it, I think it's a full marathon. It's like a century bike ride or something like that. It's an astronomical amount of everything. Whereas the sprint triathlon being the shortest, I think it's a 3.6-mile run, so a little over a 5K run, a 10-mile bike ride, and a quarter-mile swim, I want to say, something like that. But they're each scaled down to the rough equivalent of a 5K but in each of the different events. So you swim, and then you bike, and then you run. And so I'm going to try that, or at least I'm going to try to try. It's in September, and now is not September. So I have a lot of time between now and then to do some swimming, which I haven't done...like, I've swum but not in a serious way, not in an intentional way. So I got to figure out if I still know how to swim, probably get better at biking, and do a little bit of running, and it's going to be great. It's going to be a lot of fun. I'm super excited about it. Only a little terrified. STEPH: I think this is where as your co-host coach, which you have not asked me to be, where I would say something about there is no try, to mimic Yoda. [laughs] CHRIS: Yep, yep. Yep. Do or do not. Sprint or sprint not. There is no trying. Oh, were you making a try pun there? STEPH: I didn't go that far, but you just brought it home. I see where you're going. [laughs] CHRIS: This is pretty much what I do professionally is I just take words, and I roll them around until I find something else to do with them. So glad that we got there together. STEPH: Well, I'm really excited to hear about this. I don't know anyone that's trained for a triathlon. I think that's true. Yeah, I don't think I know anyone that's trained for a triathlon. So I'm curious to hear about how that goes because that sounds intense, friend. CHRIS: I think so. None of the individual segments sound that bad but stitching them all together, and I think the transitions are some of the tricky parts there. So yeah, it'll be fun. It's something I find...I used to never run; that was the thing. Like, deeply true in my head was that I'm not a runner. This is just a true fact about me. And then I ran a 5K one year for...it was like a holiday 5K fun run with friends. And every bit of the training leading up to it was awful. I did Couch to 5K. I hated it. My story in my head of I'm not a runner was proven with every single training run. Man, did I hate it. And then something magical happened on the day that I actually ran the race, and it was fun. And I was out there, and there was the energy of being in this group of people. But it was competitive and not competitive in this really interesting way. And then it ended, and we were just hanging out in a parking lot, and they gave us beer. And I was like, well, this is actually delightful. Maybe I actually like this thing. And so I've run a bunch of different races. And I've found that having a race to train for, and by train, I just mean some structured attempt at running, has been really enjoyable and useful for me. So yeah, this is just ratcheting that up a tiny bit. I've done a couple of half marathons is the high watermark so far. It's a good distance. But I don't know that a full marathon makes sense; that's a real commitment. And I'm looking to move laterally rather than just keep getting more complex in my running. So we're trying the shortest possible triathlon that I know of. STEPH: I am such a believer that exercise should be fun, so I love that. Like, I'm not a runner, but then you get around people, and it's exciting. And then there's that motivation, and then there's a fun ending with beers that totally jives with me. Because sure, I can go to the gym; I can lift weights, I can make myself exercise. There's some fun to it. But I strongly prefer anything that's more of like a sport or group exercise; that's just so much more fun. Well, super cool. Well, I'm excited. I would ask you all the details about your bike, but I know nothing. Do you want to share details about your bike? There may be other people that are interested. CHRIS: Oh yeah, my bike. I went to the bike store, and I said, "Could I have a bike, please?" And then they toured me around and showed me all the fancy...they were like, "This is our most modest entry-level bike." And then they kept walking around and showing me fancier bikes. And I was like, "Can we go back to that first one? That one seemed great." STEPH: [laughs] CHRIS: Because it got all of the checkboxes I was looking for, which is basically it's a bike. So actually, the specifics on it are it's a hybrid bike, so like a mix between road, and I don't even know the other road bikes I know of, and maybe it's trail. But I don't think it's meant for going on the trail. But for me, it'll be fine for what I'm trying to do as far as I understand it. It's technically a fitness hybrid, which I was like, oh, fancy. It's a fitness bike; look at me go. But it was basically just like, I would like a bike. General-purpose hybrid seems like the thing that makes sense. So I got a hybrid bike. And that's where I'm at. Oh, and I got a helmet because that seems like a smart move. STEPH: Nice. Yeah, the bike I own is also one of those hybrids where it's like…because when I moved to Boston...and lots of people have the road bikes, but their tires are just so skinny; it made me nervous. And so I saw one of the hybrid bikes, and I was like, that one. That looks a little more steady and secure, so I went with that one even though it's heavier. Do you have a name for your bike? Are you going to think of a name for your bike? CHRIS: I didn't, and I wasn't planning on it. But now that you've incepted me with this idea that I have to name my bike, of course, I have to name my bike. I'm going to need a couple of weeks to figure it out, though. We're going to have to get to know each other. And you know, something will become true in the universe for me to answer that question. But as of so far, no, I do not have a name for the bike. STEPH: Cool. I'll check back in. Yeah, it takes time to find that name. I feel you. CHRIS: [laughs] Yeah, don't make up a name. I have to find what's already true and then just say it out loud. Speaking of naming things and perhaps doing so in a frivolous way, as I mentioned earlier, the more technical topic that I want to talk about, oddly, is called Crispy Brussels Snack Hour. [laughs] So, within our dev team, we have started to collect together different things that don't quite belong on the product board, or at least they're a little more confusing. They're much more technical. In a lot of cases, they are...our form handling is a little rough. And it's the sort of thing that comes up a lot in pull requests where we'll say, "I feel like this could be improved." And we're like, "Yeah, but not in this pull request." And so then it's what do you do with that? Do you put a tech debt card in the product board? You and I have talked about tech debt cards plenty of times, and it's a murky topic. But we're trying within the team to make space and a way and a little bit of process around how do we think about these sorts of things? What are the pain points as a developer is working on the system? So to be clear, this isn't there is a bug because bugs we should just fix; that's my strong feeling, or we should prioritize them relative to the rest of the work. But this is a lower level. This is as a developer; I'm specifically feeling this sort of pain. And so we decided we should have a Trello board for it. And they were like, "Oh, what should we name the Trello board?" [laughs] And I decided in this moment I was like, "You know, if we're being honest, I've named everything very boring, very straight up the middle. We don't even have that many things to name. So we have zero frivolous names within our team. I think this is our opportunity. We should go with a frivolous name. Anybody have any ideas?" And someone had worked on a team previously where maybe it was a microservice or something like that was called crispy Brussels, like, crispy Brussels sprouts but just crispy Brussels. And so I was like, "Sure, something like that. That sounds great." And then they ended up naming it that which was funny, and fun, and playful in and of itself. But then we were like, "Oh, we should have a time to get together and discuss this." So we're now exploring how regularly we're going to do it. But we were like, let's have a meeting that is the dev team getting together to review that board. And we were like, "What do we call the meeting?" And so we went around a little bit, but we ended with the Crispy Brussels Snack Hour. STEPH: That's delightful. I love the idea of onboarding new people, and they just see on their calendar it's Crispy Brussels Snack Hour, come on down. [laughs] CHRIS: It's also got an emoji Brussel sprout and an emoji TV on either side of the words Crispy Brussels Snack Hour. So it's really just a fantastic little bit of frivolity in our calendars. STEPH: [laughs] That's delightful. How's that going? I don't think we've tried something like that explicitly in terms of, like you said, there are discussions we want to have, but they're not in the sprint. They're not tech debt cards that we want to create because, like you said, we've had conversations. So yeah, I'm curious how that's working for you. CHRIS: Well, so we've only had the one so far; it went quite well. We had a handful of different discussions. We were able to relatively prioritize this type of work within that. But one of the other things that we did was we had a conversation about this process, about this meeting, and the board. And whatnot. So we identified a couple of rules of the road or how we want to approach this that I think will hopefully be useful in trying to constrain this work because it's very easy to just like; nothing's ever perfect. And so this could very easily be a dumping ground for half-formed ideas that sound good but aren't necessarily worth the continued effort, that sort of thing. So the agenda for the meeting as described right now is async between meetings. Any of us can add new cards, ideally stated as problems and not solutions. So our form handling could use improvement. And then in the card, you can maybe make a suggestion of I think we could use this library or something like that. But rather than saying use this library or move to this library, we frame in terms of the problem, not necessarily the solution. And then, at the start of the meeting, any individual can champion a card so they can say, "Here's the thing that I really want everyone to know about that I've been feeling a lot of pain on." So it's a way for individuals who have added things to this to add a little bit more detail. Then using Trello as voting functionality, we each get a couple of votes, and we get to sprinkle them across different cards, and then using that now allows us collectively to prioritize based on those votes. And so the things that get voted up to the top we talk about; we prioritize some amount of work coming into the sprint. If it's actually going to turn into work, then it'll go onto the product board because ideally, it's moved from problem space to more of solution space even if the solution, the work to be done is do a spike on XYZ library or approach to form handling or whatever it is. But so ideally, it then moves on to the other board. The other thing that I felt was important is it's very easy for this to be a dumping ground for ideas. So my suggestion is at the end of the meeting, we sort by date, and we prune the oldest things. So it's like, if it's still hanging around and we haven't done it yet, and it's not getting voted up, then yes, we might feel some pain but not enough. It's not earning its place on this board. So that's my hope is we're weeding the Brussel sprouts garden that we have at the end of the meeting. That's roughly what we have now. We really only had the one, so that idea of pruning will probably come in later on. And it may be that this doesn't work out at all, and this ends up being tech debt cards that get stale and don't capture the truth. But I'm hopeful because there's definitely...there's a conversation to be had here. It's just whether or not we can make sure that conversation is useful and capturing the right amount of context and at the right points in time and all of that. STEPH: Yeah, I like it. I like the whole process you outlined. You know what it made me think of? It sounds like a technical retro, not that retros can't be technical; we bring up technical stuff all the time. But this one sounds like there was more technical discussion that was still looking for space to bring up. So the way that you mentioned that people add their thoughts, that it can be done async, and then you vote up, and then as things get stale, you remove them and focus on the things that the team voted for, that's really cool. I've never thought of having just a technical-specific retro. CHRIS: Yeah, definitely informed by retro. But again, just that slight honing the specific focus of this is just the dev team chatting about deeply dev-y things and making a little bit of space for that. I think the difficulty will be does this encourage us to work on this stuff too much? And that's the counterbalance that we have to have because this work can be critically important. But it can also be a distraction from features that we got to ship or bugs that are in the platform or other things like that. So that balancing act is something that I'm keeping in mind, but thus far, the way we structured it, I'm hopeful. And I'm interested in exploring it more, so we'll see where we get to. And I'll certainly report back as we refine the Crispy Brussels Snack Hour over time. STEPH: I feel like the opposite is true as well, where you have these types of concerns and things that you want to bring up. And even if they're on the board, once you get to sprint planning, there's a lot of context and conversation there that maybe the whole team doesn't have. It doesn't feel like the right moment to dive into this because you're trying to plan a new sprint. So then that stuff gets bumped down to the bottom or just never really discussed, or it gets archived. So I feel like the opposite is totally true, too, where you have this stuff, but then it never gets talked about because sprint planning is not the right place. So yeah, I'm really intrigued to see how that balance works out for y'all as well. CHRIS: Yeah, I think it's an exciting time, and we'll see where it goes. But like I said, I'm hopeful on it. But yeah, bikes, triathlons, and crispy Brussels, that's my world. Mid-roll Ad: Hi, friends, and now a quick break to hear from today's sponsor, Scout APM. Scout APM is an application performance monitoring tool that's designed to help developers find and fix performance issues quickly. With an intuitive user interface, Scout will tie bottlenecks to source code so you can quickly pinpoint and resolve performance abnormalities like N+1 queries, slow database queries, and memory bloat. Scout also recently implemented external service monitoring, adding even more granularity when it comes to HTTP requests and API calls. So give Scout a try today with a free 14-day trial and experience first-hand why developers worldwide call Scout their best friend. And as an added bonus for Bike Shed listeners, Scout will donate $5 to the open-source project of your choice when you deploy. To learn more, visit scoutapm.com/bikeshed. That's scoutapm.com/bikeshed. STEPH: I have a couple of fun things that I want to share and then something that's a little more in the techie space. The first one is there's a delightful Twitter thread that caught my attention recently that I just want to share; totally not tech-related. But this person shared a thread talking about how they help everyone on their team who's older than they are, making sure that the slang that they're using is correct in its context. And so they provided some funny examples. And then, in return, they also will translate this person's frustrations into professional corporate-speak, and it's such a good thread. So if you need a good laugh, I will make sure to include a link in the show notes. The slang is really funny, but it's actually the translation of frustrations into professional corporate-speak that that's the part that resonated with me. That was really good. [laughs] CHRIS: You shared this with me outside of this conversation, and I've read through them. Listeners out there, do not sleep on this. I highly suggest reading through this thread because it is fantastic. STEPH: The other thing that I saw is Andrea Fomera, who is a Rails developer and creates a fair amount of content...I haven't been through some of that content, but I know there's content around Rails. And specifically, there is a newer course called Learn Hotwire by Building a Forum. And she has made this totally free, and I just think that is so cool. And she shared that on Twitter, so I'll be sure to include a link in that to the show notes because Hotwire is something I haven't used yet. And so I saw this free course, and I think it would be fun to dabble and go through the course. And I know there are some other people at thoughtbot that have used it and seem really happy with it or interested in using it as well. Is that something that you've used? CHRIS: I have not. I skipped over Hotwire in my adventures. I'd found Inertia and was quite happy with that. And then, in that way that, I sometimes limit the amount of things that I'm allowed to explore on the internet in hopes of actually getting some work done; I have not spent much time. But enough folks that I deeply respect are very excited about Hotwire that it remains in the like; I would love to have an afternoon just to poke around with that. So I may take a look at this, although I don't know, I'm probably still in my moratorium. I'm not allowed to look at new frameworks for a little while time period. But I hear great things. STEPH: That's fair. That's also what I've heard. I've heard great things. So yeah, I just figured I would share that in case anybody else is interested in looking for a course that they could take and also dabble at Hotwire. The other thing that's on my mind is more the type of projects that I'm really getting a lot of joy from. Because I've known about myself for a while that greenfield projects are nifty, but they're not my thing. They're not the thing that brings me a lot of joy. It's just kind of nice. You got your own space, and you're building from the ground up, cool, cool, cool. But this one, I found that the projects that I'm really starting to gravitate towards are what I've heard someone else call Rails Rescue projects. So those are the projects where they have been around for a while, or they've just been built in a way that the data modeling structure makes it really hard to implement new features. Maybe there's a lack of test coverage that makes it really risky to ship new work or to make changes. There are lots of bug reports and errors that the team is fighting with. So then that type of work comes down to where you're trying to either increase stability for the application and for users and/or you're looking to increase developer acceleration. And I really, really liked those projects. That's the type of project that I've been a part of for...I think my last couple of clients have been in that way. I don't know that they would describe it that way, that it's a Rails Rescue project. But if I can see that opportunity where I see there's a stability issue or developers are feeling a lot of pain in one area, then that's the portion of the application, the portion of the team that I'm going to gravitate towards. Or like the current work that I'm doing where we're really focused on testing and making some improvements there or reducing that pain that the team is feeling around how long CI takes to run or the flakiness because then you're having to re-verify your CI runs. I like that work. It's a bit slow and frustrating, so it does seem to require a patient person. You also have to have lots of metrics that are guiding you because you can have a lot of assumptions around I'm going to make this improvement, but it's going to take effort to get there. And it'd be great if I can validate that effort upfront. So I feel like a lot of my time is spent more around metrics, and data, and excel sheets than necessarily coding. I don't know if that's great, but it's part of the work. There's a balance there. So I just found that interesting. I don't think I would have thought this is something I was interested in until now that I've been on these projects for a while. And I've started noticing a theme where I really enjoy them. Although I realize looking back at former Stephanie days when I was going through Launch Academy and learning to code, I really thought I wanted to be in DevOps. DevOps seemed like the cool kids' corner. They knew how the internet worked. They knew what was happening. They were making it live. And I just thought it seemed really cool. For the record, it is still a cool kids' corner. But I have also learned that the work-life balance isn't great with DevOps because you just never know when you're going to be on call. And that really stood out to me as something that I didn't want to do. And I do like building some features. But essentially, it's that developer acceleration that I really liked because they were the ones that were coming and often building tools and making it easier for then people to then ship their code and get it out into the world and triage. And so I liked the fact that their users were developers versus the people using the application as much, although, I guess, technically both. But the people they were often striving to help the most was the internal team, and that resonated with me. So I guess I have eventually found my way into that space. It wasn't through DevOps, but it is now through this idea of projects that need some rescuing. CHRIS: I love that you've spent enough time now to figure out what it is that draws you in the work and the shape of projects that is meaningful to you. Interestingly, I find myself not on the opposite side of things...you know, we're always looking for a disagreement, and this isn't a disagreement, but this is a thing on which we differ a surprising amount because I do like the early-stage stuff, the new, the breaking ground, all of that exciting whatnot. But how do I not make this a more complicated statement? I appreciate that you have the point of view that you do. I think the world needs more of what you're doing than the inclination that I have, like; I want to start something bright, and fresh, and new, and I can see so much progress immediately in front of me. And this is amazing. But the hard, meaningful work like maintenance, and support, and legacy, and rescue where necessary is such a critical aspect of the work. I see this in open source so often where there are people who are like; I made an open-source project; this is great. I hacked for a bunch of weekends, and look; I made a thing. And then the support burden builds up. And open source can be this wildly undervalued thing overall. And the maintenance of open source is even more so, and you have this asymmetry between the people that are using it and don't think that their voice is one of the thousands that are out there requesting a new feature or anything like that. The handful of people that I see out there in the world that come along later in the lifespan of an open-source project and just step in to do maintenance, my goodness, is that heroic work, just quiet, necessary heroic work. And what you're describing feels sort of similar but at the project level. And I don't know; I'm sort of like silent. I'm out loud on a podcast, not silently at all judging myself because I'm like, I feel like you're doing the thing over there. That seems like a good thing. But I also like my early projects... [laughs] STEPH: I think they're...I mean, we need each other. I need you to start the code, and the applications for them to then need some help down the road [laughs] to [crosstalk 24:30]. CHRIS: But I need to do a bad enough job that we have to be rescued by you. STEPH: [laughs] CHRIS: Hey, don't you worry, friend, I'm doing a terrible...no, I think I'm doing an okay [laughter] job. Hopefully, I'm avoiding those traps, but it's hard to know when you're writing legacy code, you know. STEPH: It is hard for the reasons we were talking about earlier. Like, those technical discussions build-up, and then if you don't really have a space to then address it, then it just keeps getting sidelined until you suddenly get to this point of it's either we come to a grinding halt because we can't ship work, or we find ways to start bringing this into our process. And so that's the other part of the Rails Rescue projects is often looking at the team's process and figuring out, okay, instead of hiring consultants to come in and then try to help with this, how else can they also integrate this into their own project? So then, once thoughtbot lives, they now have ownership of this, and they can carry it forward as well. There is an aspect of this work that I'm still working on, and it comes around to the definition of work because if you go into a team or a project that's like, hey, we really need help with X. We really need help with addressing all these errors. Or we really need help improving developer happiness or getting test coverage in place. Finding out exactly how you're going to tackle that, are you going to join a team of the other developers? Like, are you looking for more of a mentorship? Like, hey, we're going to work alongside your team to then mentor them to then bring this into their own process and their own habits, so then they feel empowered to address this in the future. Are we doing this more as a triage where then we have a specific goal or two that then we're going to meet? And then once we get stuff out of this on fire state, then maybe we start pairing with other people. Or are we going to work closely with the people who are fighting fires with the bug reports and the errors? There are a bunch of different ways that you can tackle that. And I think it really helps define the success of that engagement and then your outcomes because otherwise, I feel like you can get distracted by so much. Because there's so much that's going to try to get your attention that you want to work on and fix. So you have to be very upfront about there are different areas that we can work on. Let's figure out some metrics together that we're really going after to then help define what does success look like for this first iteration of our work? And then what's the long-term plan for this work? Then how do we keep it going forward? How do we empower the team to keep this work going forward? And that's an area that I've learned just from trial and error from being part of these projects. And I'm very interested in still cultivating that skill and figuring out what's the area that we're focused on? CHRIS: There's something that you said in there that I want to hone in on, which is the idea of you've learned from going on so many of these different projects, and you're carrying forward ideas that you have. But I think more generally, there's something interesting in what you were just saying there around you've worked on a bunch of different projects at different organizations with certain things that they were great at, with certain things that they struggled with at different sizes. And you're able to bring all that experience to bear on each project. But I think also taking a step back, as you were describing, you're like, I think I've figured out what it is that I like and the type of projects that I want to do. I cannot say enough good things about working in a consultancy for a while because, my goodness, you get to try out a bunch of different stuff. And A, you get to learn a ton about how to do the work, and how to communicate, and different technologies and all of that. But you also get to figure out what it is that you might want to double down on and lean into in terms of the work. That's definitely a big part of my story. Seven years at thoughtbot, I tried a lot of different stuff, worked at a lot of different companies. And I would describe it as I found a lot of things that I didn't want. And then there's that handful of things that I really did want, and I was able to then more intentionally pursue that. So for anyone out there that's considering it, working at a consultancy is fantastic, or at least it has fantastic elements to it. It also can be complicated as you talk about finding organizations and having to, you know, if you're brought in for a certain job, but when you get there, you're like, "Ooh, I know you want me to fix bugs, but actually, I think I just need to work with your team because they're the ones writing the bugs. And why are they writing the bugs" "Well, because the salespeople are selling things, and then we have timelines." Like, we got to start at the very top of this whole pyramid and fix it. And so it can be very complicated. But there's so much that you can learn about yourself in the process, in the work, and I adored that portion of my career. STEPH: Yeah, I totally agree. Anytime someone mentions, they're like, "Oh, consultancy work. What's that like?" And I remember it was a couple of years ago I mentioned I was working for a consultancy, and they were like, "Oh, you must travel a lot." I was like, "No, [laughter] I stay put. I just work from an office in Boston." But I remember that caught me off guard because I hadn't considered that I was supposed to travel, but that makes sense that you think of consultants that travel. But when I meet people or talk to people, and they're like, "Oh, you've been at thoughtbot for five-plus years, and how's that going? And what's it like to be at a consultancy?" And exactly what you just said, it's the variety that I really like and getting to try on so many different hats and see how different teams and processes work and then identify like, oh, that worked really well for that team, or this isn't working well for that team. I have really enjoyed that. And it can be a roller coaster because you have to get really good at onboarding. You have to go through that initial phase of like; I swear I'm smart. I will get up to speed quickly, and I will learn things. But it's a period that you just have to go through with each team that you join, but you do it twice a year, maybe three times a year. And so you get comfortable with that over time. So there are definitely some challenges that then have to fit your personality and things that work for you and bring you joy. And I completely understand that it's not for everybody, just kind of I really enjoy product work, but I also really enjoy being able to move around to different teams and help folks. CHRIS: I love the idea that as a consultant, your job is to just walk through airports and high-five every Accenture billboard in it and just go up to the wall and pay your respects. But no, no, that is not our version of consulting. [laughs] STEPH: That's why I have so much time for The Bike Shed. It's because I'm just, you know, I'm in different airports high-fiving signs. And then this is my real job; Bike Shed is my real job. CHRIS: Oh, that would be fun. STEPH: [laughs] You know, I have such a fondness of Bike Shed that now something interesting has happened where someone was like, "Oh, you're bike-shedding." And they're not being mean, but they're just like, "Oh, we're totally bike-shedding," or "This is dissolving into bike-shedding." And I'm like, oh, bike-shedding, hooray. And I'm like, oh, wait, bad. [laughter] And I have to catch myself each time. CHRIS: Yeah, we've taken away a lot of the meaning. Well, I mean, have we or do we live up to it every single week? Who can say? But I, too, have a fondness for this phrase, perhaps not aligned with what it is actually meant to signify. STEPH: On a slightly different tech-related note, there is a gem that I'm really excited to check out. I saw it mentioned on the paralleltests gem, which is what helps you run your tests in parallel, and it's what we're currently using. But you can group your tests in different ways. And right now, we're using the runtime strategy where essentially then we use the output from RSpec where we know how long each file took to run. And then paralleltests will then use that data to then figure out, okay, how should I split up your test file? So then try to balance them as evenly as possible. We're at that point, though, where we've talked about tentpoles, so we have certain files that, say, take 10 minutes; other files will only take two minutes. And that balance is really throwing off our ability to then bring down the CI build time. So on paralleltests, there's reference to another gem called parallelsplit_test, where then you can run multiple test scenarios that are in one file but then split them out across different processes or different machines. And that is exactly what I want in my life right now. I haven't checked it out yet, so I feel like I'm giving a daily sync update of like, I'm going to go off and explore this thing. I will report back and see how it goes. [laughs] In the past, I usually try to say, "I've tried this thing, and this is how it went," nope, opposite today. I am sharing the thing I'm going to try, and then hopefully, it goes well. CHRIS: Well, either way, we should definitely report back. That's the truth. I like that you're leading us into this and giving us a preview. But then yeah, we'll see where we get to. That does sound like the thing you want, though. So I hope it goes well. STEPH: Yeah, we've learned at this point where we are splitting work across different machines that until we address some of those tentpole concerns, adding more machines won't help us because then a machine's going to run as long as the longest file. So we've been doing some manual work to split up those files. That's not the best, but it does help you see some results. So then, at least you know you're making progress. So now we really need to find a way to automate that because we don't want someone to have to manually figure out where are the tentpoles, split those files up, commit that, and then keep track of, like, do we have another tentpole on the horizon? We really need a gem or something to help us automate that process. So yeah, I will be happy to report back. MIDROLL AD: And now a quick break to hear from today's sponsor, Studio 3T. When you're developing applications, it can often be a chore to work with your underlying data. Studio 3T equips you with a complete set of tools to work with MongoDB data. From building queries with drag and drop, to creating complex aggregation pipelines; Studio 3T makes it easy. And now, there's Studio 3T Free, a free edition of Studio 3T, which delivers an essential core of tools. This means you can get started, for free, with Studio 3T Free, and when you're ready, you can upgrade and enjoy even more features through Studio 3T Pro and Studio 3T Ultimate. The different editions unlock more tools and additional integrations with MongoDB, SQL, Oracle, and Sybase. You can start today by downloading Studio 3T Free, which also includes a 30-day free trial of all the features of Studio 3T Ultimate, so you can try out some of the enterprise features as well. No credit card required. To start your trial, head to studio3t.com/free. That's studio3t.com/free. STEPH: Pivoting just a bit, we have a listener question. This question comes from Steve Polito. And Steve wrote in, "Longtime listener, first-time thoughboter." Yay. Yay is my addition. Anything that goes up in voice is probably my addition, [laughs] just so people know. All right, back to what Steve said. "Why do so many developers and agencies, thoughtbot included, replace the default test suite in Rails with RSpec? Not only does Rails provide a fully functional test suite by default," looking at you Minitest, "but it's also well-documented and even provides the ability to run system tests. Rails is built on the principle of convention over configuration. And it seems odd to me that so many developers want to override such a fundamental piece of framework." Thanks in advance, [singing] Steve Polito. Steve, I hope it's okay I sang your name [laughs] because we're here now. That is an awesome question. I'm going to give what may be less of an awesome answer which is, well, one; Steve highlights that people will then replace Minitest with RSpec. I haven't done that. I haven't actually gone into a project and said, "Okay, we need to replace your test suite and bring in RSpec instead." But if I'm starting out a project, I do have a heavy preference for RSpec, and frankly, that's just from experience. Like, that's what I was raised on, to say it in that way. [laughs] RSpec is what I know; it's what I'm used to. It's what, even when I joined thoughtbot, was just the framework that we used for all of our testing and what we focused on so heavily. So frankly, for me, it's just a really strong bias. I know it's something that I'm really good at. I know it's something that works really well. I know it's well-documented. I know it's also very accessible for other people to use. But actually replacing it on a different project, I don't think I would do that. I'd have to have a really strong reason, or maybe if we haven't actually started testing anything yet, to then replace it because that feels a bit aggressive to me. But then it just depends on the situation, I suppose. But yeah, overall, I just default to RSpec because that's what I'm accustomed to, and it's the testing framework that I know. CHRIS: Yeah, I think my answer is largely the same. It's the thing that I've worked with by far the most. Similarly, I've been on projects that were using Minitest, and therefore I used Minitest because it's definitely not worth the effort to switch. But in a lot of...well, I will say this, I've much less experience, and this may be less true over time. But there were many things that drew me to RSpec, and that continues to be interesting to me in the RSpec world. Even things as small as the assertion syntax, assertequal is the method that's, you know, this is how you do an assertion in Minitest, and it's assertequal expected, actual. That's the order of the arguments. It's expected first and then actual. That makes sense, probably with the expected, but I would get that wrong constantly. I do get that sort of thing wrong. They're just positional arguments that there's nothing about this that tells me which way to go. And so it's very easy to get failure messages that are inverted, and so it's just this tiny little thing. But with RSpec, we end up with expect and then in parentheses, the thing that we are expecting to equal the other thing, and it just reads a little more honestly. It fits within the Ruby mindset in my world. I want my code to be as expressive as possible, and Minitest feels much lower level to me. It feels more, you know, assert as a word is just...I'm not asserting. That just feels so formal. And so these are, again, to be clear, very, very small things, but they all add up. And there's a reason that we're using Ruby overall. And there's a reason that we're using Rails is this expressiveness is a big part of it for me, so I'll cling to that. I'll hold on to that as something that's true. Also, Rspec's mocking support, rspec-mocks as the library, I found to be really fantastic, and I've grown very comfortable working with it. And I know how and where to use that. I also have so much built-up knowledge, like the idea of when to use let and not use let in RSpec. It's just this deep thing that I know about. I'm sure there's an equivalent in the Minitest world, but I would have to have a different understanding in argument, and that conversation would just feel different. I think the other thing that's worth saying is this is a default for us at this point that I personally have not felt the need to reconsider. When I've worked on projects that have used Minitest, I certainly wasn't called to it. I wasn't like, oh, this seems really interesting; I'm going to lean into this more. I was like, I miss RSpec. And some of that is, again, just familiarity. But at the end of the day, we only have so much time to do things. And so, I firmly stand by my not reconsidering my testing option at this point. Like, RSpec does the things that I want. It does it really well. Critically, I'm able to build a system and write a test suite and maintain that test suite over time and have it tell me the truth as to whether or not my application should be deployed to production. That is the measure. That's the thing that I care about. I think it's maybe a little bit slower than Minitest, but I'm fine with that. I have solutions to that problem. And the thing that I care about is when the test suite is green, do I feel confident deploying? RSpec has helped me for years on that journey. And I've never questioned whether or not I should go back to the drawing board and revisit that consideration. So initially, it was probably because it was the thing that we were all using, and then that is for me why it has stuck around. And I love RSpec. I think how many episodes have we just said, "Thanks, RSpec," as a little aside? So we do love it in a deep way. STEPH: Probably not enough episodes have we said that. [laughs] Yeah, I like what you said where you haven't felt the need to switch over or to move away from RSpec. And I wonder, looking back at some of the earlier projects that I joined that were using RSpec, I don't know if maybe they chose RSpec at that time because RSpec had more of those features built-in, and Minitest was still working on those. Maybe they were parallel at the time; I'm not sure. But I like what you said about you just haven't had a need to go back and change. At this point, if I switched over to Minitest, it would definitely be a learning curve for me, which is totally fine. But yeah, I'm just happy with it, so I stick with it. And I also appreciate that idea that, yeah, unless you're new in a project, I wouldn't encourage someone to then switch over to something else unless I feel like there's just a lot of pain for some reason with the current testing setup. There has to be a reason. There has to be a drive. It can't be just a personal bias of like, I know this thing, so I want to use it. There's got to be a better reason that benefits the whole team versus just a personal preference. But overall, I think it comes down to for us; it's just a choice because it's the familiar choice. It's the one that we know. But I think Minitest and RSpec are both so widely supported. I was thinking about that convention over configuration. And yes, Rails ships with Minitest, but RSpec is so common that I don't feel like I'm breaking convention at that point. They're both so widely supported and used that I feel very comfortable going with either option. And then it's just my personal preference for RSpec. So thanks, Steve, for sending in that question. And for anyone else that has a question that you would love to share with Chris and I, you can reach us in a couple of different ways. You can reach us on Twitter via @_bikeshed. You can also go to the website, bikeshed.fm/content. We will drop some links in the show notes. But if you go there, then you can send a question or also email us directly at hosts@bikeshed.fm. And we're running a little low on listener questions, so we would love to have a listener question from you. And we would love to talk about anything that y'all want to talk about, okay, within reason, you know, triathlons, Brussel sprouts, things like that. All of that falls within the wheelhouse. CHRIS: Normal stuff. STEPH: Normal stuff, yeah. CHRIS: And to be clear, despite the fact that Steve did recently become a thoughtboter, you don't have to be a thoughtboter to send in a listener question. [laughs] In fact, it's much more common to not be a thoughtboter when sending in a listener question. But we'll take them from anybody. We're happy to chat with you. STEPH: On that note, shall we wrap up? CHRIS: Let's wrap up. The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

The Bike Shed
333: Tapas

The Bike Shed

Play Episode Listen Later Apr 12, 2022 41:53


Being pregnant is hard, but this tapas episode is good! Steph discovered and used a #yelling Slack channel and attended a remote magic show. Chris touches on TypeScript design decisions and edge cases. Then they answer a question captured from a client Slack channel regarding a debate about whether I18n should be used in tests and whether tests should break when localized text changes. This episode is brought to you by ScoutAPM (https://scoutapm.com/bikeshed). Give Scout a try for free today and Scout will donate $5 to the open source project of your choice when you deploy. Emma Bostian (https://twitter.com/EmmaBostian) Ladybug Podcast (https://www.ladybug.dev/) Gerrit (https://www.gerritcodereview.com/) Gregg Tobo the Magician (https://astonishingproductions.com/) Sean Wang - swyx - better twitter search (https://twitter.com/swyx/status/1328086859356913664) Twemex (https://twemex.app/) GitHub Pull Request File Tree Beta (https://github.blog/changelog/2022-03-16-pull-request-file-tree-beta/) Sam Zimmerman - CEO of Sagewell Financial on Giant Robots (https://www.giantrobots.fm/414) TypeScript 4.1 feature (https://devblogs.microsoft.com/typescript/announcing-typescript-4-1/) The Bike Shed: 269: Things are Knowable (Gary Bernhardt) (https://www.bikeshed.fm/269) TSConfig Reference - Docs on every TSConfig option (https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess) Rails I18n (https://guides.rubyonrails.org/i18n.html) This episode is brought to you by Studio 3T (https://studio3t.com/free). Try Studio 3T's full suite of features for 30 days, no payment details needed. Become a Sponsor (https://thoughtbot.com/sponsorship) of The Bike Shed! Transcript: CHRIS: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Chris Toomey. STEPH: And I'm Steph Viccari. CHRIS: And together, we're here to share a bit of what we've learned along the way. So, Steph, what's new in your world? STEPH: Hey, Chris. There are a couple of new things in my world, so one of them that I wanted to talk about is the fact that being pregnant is hard. I feel like this is probably a known thing, but I feel like I don't hear it talked about as much as I'd really like, especially in sort of like a professional context. And so I just wanted to share for anyone else that may be listening, if you're also pregnant, this is hard. And I also really appreciate my team. Going through the first trimester is typically where you experience a lot of morning sickness and fatigue, and I had all of that. And so I was at the point that most of my days, I didn't even start till about noon and even some days, starting at noon was a struggle. And thankfully, the thoughtbot client that I'm working with most of the teams are on West Coast hours, so that worked out pretty well. But I even shared a post internally and was like, "Hey, I'm not doing great in the mornings. And so I really can't facilitate any morning meetings. I can't be part of some of the hiring intros that we do," because we like to have a team lead provide a welcoming and then closing for anyone that's coming for interview day. I couldn't do those, and those normally happen around 9:00 a.m. for Eastern Time. And everybody was super supportive of it. So I really appreciate all of thoughtbot and my managers and team being so great about this. Also, the client team they're wonderful. It turns out growing a little human; I'm learning how hard it is and working full time. It's an interesting challenge. Oh, and as part of that appreciation because…so there's just not a lot of women that I've worked with. This may be one of those symptoms of being in tech where one, I haven't worked with tons of women, and then two, working with a woman who is also pregnant and going through that as well. So it's been a little bit isolating in that experience. But there is someone that I follow on Twitter, @EmmaBostian. She's also one of the co-hosts for the Ladybug Podcast. And she has been just sharing some of her, like, I am two months sleep deprived. She's had her baby now, and she is sharing some of that journey. And I really appreciate people who just share that journey and what they're going through because then it helps normalize it for me in terms of what I'm feeling. I hope this helps normalize it for anybody else that might be listening too. CHRIS: I certainly can't speak to the specifics of being pregnant. But I do think it's wonderful for you to use this space that we have here to try and forward that along and say what your experience is like and share that with folks and hopefully make it a little bit better for everyone else out there. Also, you snuck in a sneaky pro-tip there, which is work on the East Coast and have a West Coast team. That just sounds like the obvious correct way to go about this. STEPH: That has worked out really well and been very helpful for me. I'm already not a great morning person; I've tried. I've really strived at times to be a morning person because I just have this idea in my head morning people get more stuff done. I don't think that's true, but I just have that idea. And I'm not the world's best morning person, so it has worked out for many reasons but yeah, especially in helping me get through that first trimester and also just supporting family and other things that are going on. Oh, I also learned a pro-tip about Twitter. This is going to seem totally random, but it was relevant when I was searching for stuff on Twitter [laughs] that was related to tech and pregnancy. But I learned...because I wanted to be able to search for something that someone that I follow what they said but I couldn't remember who said it. And so I found that in the search bar, I can add filter:follows. So you can have your search term like if you're looking for cake or pregnancy, or sleep-deprived and then look for filter:follows, and then that will filter the search results to everybody that you follow. I imagine that that probably works for followers too, but I haven't tried it. CHRIS: I like the left turn you took us on there but still keeping it connected. On the topic of Twitter search, they apparently have a very powerful search, but it's also hidden, and you got to know the specific syntax and whatnot. But there is a wonderful project by Shawn Wang, AKA Swyx, on the internet, bettertwitter.netlify.com is the URL for it. I will share a link to his tweet introducing it. But it's a really wonderful tool that just provides a UI for all of these different filters and configurations. And both make discoverability that much better and then also make it easy to just compose one of these searches and use that. The other thing that I'll recommend is, I think it's a Chrome plugin. I'm guessing is what I'm working with here like a browser extension, but it's called Twemex, T-W-E-M-EX. And there's a sidebar in Twitter now, which just seems wonderful and useful. So as I'm looking at a Swyx post here, or a tweet as they're called on Twitter because I know that vernacular, there's a sidebar which is specific to Shawn Wang. And there's a search at the top so I can search within it. But it's just finding their most popular tweets and putting that on a sidebar. It's a very useful contextual addition to Twitter that I found just awesome. So that combination of things has made my Twitter experience much better. So yeah, we'll have show notes for both of those as well. STEPH: Nice. I did not know about those. This may cause someone to laugh at me because maybe it's easier than I think. But I can never remember that advanced search that Twitter does offer; I have to search it every time. I just go to Google, and I'm like, advanced Twitter search, and then it brings up a site for me, and then I use that as the one that Twitter does provide. But yeah, from the normal UI, I don't know how to get there. Maybe I haven't tried hard enough. Maybe it's hidden. CHRIS: It's like they're hiding it. STEPH: Yeah, one of those. [laughs] CHRIS: It's very costly. They have to like MapReduce the entire internet in order to make that search work. So they're like, well, what if we hide it because it's like 50 cents per query? And so maybe we shouldn't promote this too much. STEPH: [laughs] CHRIS: And let's just live in the moment, everybody. Let's just swim in the Twitter stream rather than look back at the history. I make guesses about the universe now. STEPH: [laughs] On a different note, I also discovered at thoughtbot in our variety of Slack channels that we have a yelling channel, and I had not used it before. I had not hung out there before. It's a delightful channel. It's a place that you just go, and you type in all caps. You can yell about anything that you would like to. And I specifically needed to yell about Gerrit, which is the replacement or the alternative that we're using for GitHub or GitLab, or Bitbucket, or any of those services. So we're using Gerrit, and I've been working to feel comfortable with the UI and then be able to review CRs and things like that. My vernacular is also changing because my team refers to them as change requests instead of pull requests. So I'm floating back and forth between CRs and PRs. And because I'm in Gerrit world, I missed some of the updates that GitHub made to their pull request review screen. And so then I happened to hop in GitHub one day, and I saw it, and I was like, what is this? So that was novel. But going back to yelling, I needed to yell about Gerrit because I have not found a way to collaborate with someone who has already pushed up changes. I have found ways that I can pull their changes which then took a little while. I found it in a sneaky little tab called download. I didn't expect it to be there. But then the actual snippet it's like, run this in your terminal, and this is then how you pull down the changes. And I'm like, okay, so I did that. But I can't push to their existing changes because then I get like, well, you're not the owner, so we're going block you, which is like, cool, cool, cool. Okay, I kind of get that because you don't want me messing up somebody else's content or something that they've done. But I really, really, really want to collaborate with this person, and we're trying to do something together, and you're blocking me. And so I had to go to the yelling channel, and I felt better. And I'm yelling again. [laughs] Maybe I don't feel that great because I'm getting angry again talking about it. CHRIS: You vented a little into the yelling channel; maybe not everything, though. STEPH: Yeah, I still have more to vent because it's made life hard. Every time I wanted to push up a change or pull down someone else's changes, there are now all these CRs that then I just have to go and abandon, which is then the terminology for then essentially closing it and ignoring it, so I'm constantly going through. And if I do want to pull in changes or collaborate, then there's a flow of either where I abandon mine, or I pull in their changes, but then I have to squash everything because if you push up multiple commits to Gerrit, it's going to split those commits into different CRs, don't like that. So there are a couple of things that have been pain points. And yeah, so plus-one for yelling channels, let people get it out. CHRIS: Okay, so definitely some feelings that you are working through here. I'm happy to work together as a team to get through some of them. One thing that I want to touch on is you very quickly hinted at GitHub has got a bunch of new things that are cool. I want to talk about those. But I want to touch [laughs] on an anecdote. You talked about pushing something up to someone else's branch. You're like, oh, you know, I made some changes locally, and I'm going to push them up. I had an interesting experience once where I was interacting with another developer. I had done some code review. They weren't quite understanding where I was. They had a lot of questions. And finally, I said, you know what? This will just be easier. Here, I pushed up a commit to your branch, so now you can see what I'm talking about. And I thought of this as a very innocuous act, but it was not interpreted that way. That individual interpreted it in a very aggressive sort of; it was not taken well. And I think part of that was related to I think of Git commits as just these little ephemeral things where you're like, throw it out, feel free. This is just the easiest way for me to communicate this change in the context of the work that you're doing. I thought I was doing a nice favor thing here. That was not how it went. We had a good conversation after I got to the heart of where we both were emotionally on this thing. It was interesting. The interaction of emotion and tech is always interesting. But as a result, I'm very, very careful with that now. I do think it's a great way as long as I've gotten buy-in from the person beforehand. But I will always spot check and be like, "Hey, just to confirm, I can just push up a commit to your branch, but are you okay with that? Is that fine with you?" So I've become very cautious with that. STEPH: Yeah, that feels like one of those painful moments where it highlights that the people that you work with that you are accustomed to having a certain level of trust or default trust with those individuals, and then working with someone else that they don't have that where the cup is half-full in terms of that trust, or that this person means well kind of feelings towards a colleague or towards someone that they're working with. So it totally makes sense that it's always good to check and just to be like, "Hey, I'd love to push up some changes to your branch. Is that cool?" And then once you've established that, then that just makes it easier. But I do remember that happening, and yeah, that was a bit painful and shocking because we didn't see that coming and then learned from it. CHRIS: I do think it's an important thing to learn, though, because for me, in that moment, this was this throwaway operation that I thought almost nothing of, but then another individual interpreted it in a very different way. And that can happen, that can happen across tons of different things. And I don't even want to live in the idealized world where it's just tech; we're just pushing around zeros and ones; there's no human to this. But no, I actually believe it's a deeply human thing that we're doing here. It's our job to teach the computers to be a little closer to us humans or something like that. And so it was a really pointed clarification of that for me where it was this thing that I didn't even think once about, no less twice, and yet someone else interpreted it in such a different way. So it was a useful learning situation for me. STEPH: Yeah, I totally agree. I think that's a really wise default to have to check in with people before assuming that they'll be comfortable with something that we're comfortable with. CHRIS: Indeed. But shifting back to what you mentioned of GitHub, a bunch of new stuff came in GitHub, and you were super excited about it. And then you went on to say other things about another system. [laughs] But let's talk about the great things in GitHub. What are the particular ones that have caught your eye? I've seen some, but I'm intrigued. Let's compare notes. STEPH: So this is one of those where I hadn't seen GitHub in quite a while, and then I hopped in, and I was like, this is different. But some of the things that did stand out to me right away is that on the left-hand side, I can see all of the files that have been changed, and so that's a really nice tree where I just then immediately know. Because that was one of the things that I often did going to a PR is that I would see what files are involved in this change because it was just a nice overview of what part of the applications am I walking through? Are there tests for this? Have they altered or added tests? And so I really like that about it. I'm sure there's other stuff. But that is the main thing that stood out to me. How about you? CHRIS: Yeah, that sidebar file tree is very, very nice, which I find surprising because I don't use a file tree in my editor. I only do fuzzy finding to jump to files. But I think there's something about whenever GitHub had the file list; these are all the files that are changed. I'm like, this is just noise. I can't look at this and get anything out of it. But the file tree is so much more...there's a shape to it that my brain can sort of pattern match on. And it's just a much more discoverable way to observe that information. So I've really loved that. That was a wonderful one. The other one that I was surprised by is GitHub semantic code analysis; stuff has gotten much, much better over time subtly. I didn't even notice this happening. But I was discussing something with someone today, and we were looking at it on GitHub, and I just happened to click on an identifier, and it popped up a little thing that says, "Oh, do you want to hop to the references or the definition of this?" I was like, that is what I want to do. And so I hopped to the definition, hopped to the definition of another thing, and was just jumping around in the code in a way that I didn't know was available. So that was really neat. But then also, I was in a pull request at one point, and someone was writing a spec, and they had introduced a helper just like stub something at the bottom of a given spec file. And it's like, I feel like we have this one already. And I just clicked on the identifier. I think it might have actually been a matcher in RSpec, so it was like, have alert. And I was like, oh, I feel like we have this one, a matcher specific to flash message alerts on the page. And I clicked on it, and GitHub provided me a nice little inline dialog that showed me all of the definitions of have alert, which I think we were up to like four of them at that point. So it had been copied and pasted across a couple of different files, which I think is totally fine and a great way to start, but they were very similar implementations. I was like, oh, looks like we actually already have this in a couple of places, maybe we clean it up and extract it to a common spec support thing, and ta-da, I was able to do all of that from the GitHub pull requests UI. And I was like, this is awesome. So kudos to the GitHub team for doing some nifty stuff. Also, can I get into the merge queue? Thank you. ... STEPH: [laughs] There it is. That is very cool. I didn't know I could do that from the pull request screen. I've seen it where if I'm browsing code that, then I can see a snippet of where everything's defined and then go there, but I hadn't seen that from the pull request. I did find the changelogs for GitHub that talk about the introduction of having the tree, so we'll be sure to include a link in the show notes for that too. But yes, thank you for letting me use our podcast as a yelling channel. It's been delightful. [laughs] Mid-roll Ad Hi, friends, and now a quick break to hear from today's sponsor, Scout APM. Scout APM is an application performance monitoring tool that's designed to help developers find and fix performance issues quickly. With an intuitive user interface, Scout will tie bottlenecks to source code so you can quickly pinpoint and resolve performance abnormalities like N+1 queries, slow database queries, and memory bloat. Scout also recently implemented external service monitoring, adding even more granularity when it comes to HTTP requests and API calls. So give Scout a try today with a free 14-day trial and experience first-hand why developers worldwide call Scout their best friend. And as an added bonus for Bike Shed listeners, Scout will donate $5 to the open-source project of your choice when you deploy. To learn more, visit scoutapm.com/bikeshed. That's scoutapm.com/bikeshed. CHRIS: Well, speaking of podcasts, actually, there was an interesting thing that happened where the CEO of Sagewell Financial, the company of which I am the CTO of, Sam Zimmerman is his name, and he went on the Giant Robots Podcast with Chad a couple of weeks ago. So that is now available. We'll link to that in the show notes. I'll be honest; it was a very interesting experience for me. I listened to portions of it. If we're being honest, I searched for my name in the transcript, and it showed up, and I was like, okay, that's cool. And it was interesting to hear two different individuals that I've worked with either in the past or currently talking about it. But then also, for anyone that's been interested in what I'm building over at Sagewell Financial and wants to hear it from someone who can probably do a much better job of pitching and describing the problem space that we're working in, and all of the fun challenges that we have, and that we're hopefully living up to and building something very interesting, I think Sam does a really fantastic job of that. That's the reason I'm at the company, frankly. So yeah, if anyone wants to hear a little bit more about that, that is a very interesting episode. It was a little weird for me to listen to personally, but I think everybody else will probably have a normal experience listening to it because they're not the CTO of the company. So that's one thing. But moving on, I feel like today's going to be a grab bag episode or tapas episode, lots of small plates, as we were discussing as we were prepping for this episode. But to share one little thing that happened, I've been a little more removed from the code of late, something that we've talked about on and off in previous episodes. Thankfully, I have a wonderful team that's doing an absolutely fantastic job moving very rapidly through features and bug fixes and all those sorts of things. But also, I'm just not as involved even in code review at this point. And so I saw one that snuck through today that, I'm going to be honest, I had an emotional reaction to. I've talked myself down; we're fine now. But the team collectively made the decision to move from a line length of 80 characters to a line length of 120 characters, and I had some feelings. STEPH: Did you fire everybody? [laughs] CHRIS: No. I immediately said, doesn't really matter. This is the whole conversation around auto-formatting tools is like we're just taking the decision away. I personally am a fan of the smaller line length because I like to have multiple files open left to right. That is my reason for it, but that's my reason. A collective of the developers that are frankly working more in the code than I am at this point decided this was meaningful. It was a thing that we could automate. I think that we can, you know, it's not a thing that we have to manage. So I was like, cool. There we go. The one thing that I did follow up on I was like, okay; y'all snuck this one in, it's fine, I'm fine with it. I feel fine; everything's fine. But let's add that to the git-blame-ignore-revs file, which is a useful thing to know about. Because otherwise, we have a handful of different changes like this where we upgrade Prettier, and suddenly, the manner in which it formats the files changes, so we have to reformat everything at once. And this magical file that exists in Git to say, "Hey, ignore this revision because it is not relevant to the semantic history of the app," and so it also takes that decision out of the consideration like yeah, should we reformat or not? Because then it'll be noisy. That magical file takes that decision away, and so I love that. STEPH: I so love the idea because you took vacation recently twice. So I love the idea of there was a little coup and people are applauding, and they're like, while Chris is on vacation, we're going to merge this change [laughs] that changes the character line. And yeah, that brings me joy. Well, I'm glad you're working through it. Sounds like we're both working through some hard emotional stuff. [laughs] CHRIS: Life's tricky, is all I'm going to say. STEPH: I am curious, what prompted the 80 characters versus 120? This is one of those areas that's like, yeah, I have my default preference like you said. But I'm more intrigued just when people are interested in changing it and what goes with it. So do you remember one of the reasons that 120 just suited their preferences better? CHRIS: Frankly, again, I was not super involved in the discussion or what led them to it. STEPH: [laughs] CHRIS: My guess is 120 is used...I think 80 is a pretty common one. I think 120 is another of the common ones. So I think it's just a thing that exists out there in the mindshare. But also, my guess is they made the switch to 120 and then reformatted a few files that had like, ah, this is like 85 characters, and that's annoying. What does it look like if we bump it up? And so 120 provided a meaningful change of like, this is a thing that splits to four lines if we have an 80 character thing, or it's one line if it's 120 characters, which is a surprising thing to say, but that's actually the way it plays out in certain cases because the way Prettier will break lines isn't just put stuff on the next line always. It's got to break across multiple lines, actually. All right, now that we're back in the opinion space, I have a strong one. STEPH: This is The Bikeshed. We can live up to that name. [laughs] CHRIS: So I do want an additional configuration in Prettier Ruby. This is the thing I'll say. Maybe I can chase down Kevin Newton and see if he's open to this. But when Prettier does break method call with arguments going into it but no parens on that method call, and it breaks out to multiple lines, it does the dangling indent thing, which I do not like. I find it distasteful; I find it noisy, the shape of the code. I'm a big fan of the squint test. I know that from Sandi Metz, I believe, or maybe it's Avdi Grimm. I associate it with both of them in my mind. But it's just a way to look at the code and kind of squint, and you see the shape of it, and it tells you something. And when the lines break in that weird way, and you have these arbitrary dangling indents, the shape of the code is broken up. And I don't feel so strongly. I actually regularly stop myself from commenting on pull requests on this because it's very easy. All you need to do is add explicit parens, and then Prettier will wrap the line in what I believe is a much more aesthetically pleasing, concise, consistent, lots of other good adjectives here that are definitely just my preferences and not facts about the world. But so what I want is, Prettier, hey, if you're going to break this line across multiple lines, insert the parens. Parens are no longer optional for breaking across multiple lines; parens are only optional within a given line. So if we're not breaking across lines, I want that configuration because this is now one of those things where I could comment on this. And if they added the optional parens, then Prettier would reform it in a different way. And I want my auto formatter don't give me ways to do stuff. Like, constrain me more but also within the constraints of the preferences that I have, please, thank you. STEPH: I love all the varying levels there [laughter] of you want a thing, but you know it's also very personal to you and how you're walking that line and hopping back and forth on each side. I also love the idea. We have the idea of clean code. I really want something that's called distasteful code now [laughs] where you just give examples of distasteful code, yes. Well, I wish you good luck in your journey [laughs] and how this goes and how you continue to battle. I also appreciate that you mentioned when you're reviewing code how you know it's something that you really want, but you will refrain from commenting on that. I just appreciate when people have that filter to recognize, like, is this valuable? Is it important? Or, like you said, how can we just make this more of the default so then we don't even have to talk about it? And then lean into whatever the default the team goes with. CHRIS: Well, thank you. I very much appreciate that because, frankly, it's been very difficult. STEPH: I do have something I want to yell about but in a very positive way or pranting as we determined or, you know, raving, the actual real term that wonderful listeners pointed out to us. CHRIS: Prant for life. That's my stance. STEPH: We had a magic show at thoughtbot. It was all remote, but the wonderful Gregg Tobo, the magician, performed a magic show for us where we all showed up on Zoom. And it was interactive, and it was delightful, and it was so much fun. And so if you need something fun for your team that you just want to bring folks together, highly recommend. I had no idea I was going to enjoy a magic show this much, but it was a lot of fun. So I'll be sure to include some links in the show notes in case that interests anyone. But yeah, magic. I'm doing jazz hands. People can't see it, but magic. I like how you referred earlier, saying that today is more of like a tapas episode. And I'm realizing that all of my tapas are related to being pregnant, yelling, and magic shows, and I'm okay with that. [laughs] But on that note, what else is on your tapas plate? CHRIS: Actually, a nice positive one that came into the world...I always like when we get those. So this is interesting because I was actually looking back at the history, and I had Gary Bernhardt on The Bike Shed back in Episode 269. We'll include a link in the show notes. But we talked a bunch about various things, including TypeScript. And I was lamenting what I saw as a pretty big edge case in TypeScript. So the goal of TypeScript is like, all right, JavaScript exists, this is true. What can we do on top of that? Let's not fundamentally change it, but let's build a type system on top of it and try and make it so that we can enforce correctness but understand that JavaScript is a highly dynamic language and that we don't want to overconstrain and that we've got to meet it where it is. And so one of the design decisions early on with TypeScript is if you have an array and you say like it's an array of integers, so you have typed that array to be this is an array of int, or it will be an array of number in JavaScript because JavaScript doesn't have integers; they only have numbers. Cool. [laughs] Setting aside other JavaScript variables here, you have an array of numbers. And so if you use element access to say, like, say the name of array is array of nums and then use brackets and you say zero, so get me the first element of that array. TypeScript will infer the type of that to be a number. Of course, it's a number, right? You got an array of numbers, you take a number out of it, of course, you're going to have a number, except you know what's also an array of numbers? An empty array. Well, of course. So there's no way for TypeScript because that's a runtime thing, whether or not the array is full of things or not. Or imagine you get the third element from the array. Well, JavaScript will either return you the third element, which indeed is a number, or undefined because there's no third element in this array. So that is an unfortunate but very understandable edge case that TypeScript was like, listen, this is how JavaScript works. So we're not going to…frankly, we don't think the people embracing TypeScript and bringing it into their world would accept this amount of noise because this is everywhere. Anytime you interact with an array, you are going to run into this, this sort of uncertainty of did I actually get the thing? And it's like, yeah, no, I know how many things are in the array that I'm working with. Spoiler, you maybe don't is the answer. And so, we ran into this edge case in our codebase. We were accessing an element, but TypeScript was telling us, "Yes, definitively, you have an object of that type because you just got it out of an array, which is an array of that type." But we did not; we had undefined. And so we had, you know blah is not a method on undefined or whatever that classic JavaScript runtime error is. And I was like, well, that's very sad. But now we get to the fun part of the story, TypeScript, as of version 4.1, which came out like the week that I recorded with Gary Bernhardt, which was interesting to look at the timeline here. TypeScript has added a new configuration. So a new strictness dial that you can configure in your tsconfig called noUncheckedIndexedAccess. So if you have an array and you are getting an element out of it by index, TypeScript will say, "Hey, you got to check if that's undefined," because to be clear, very much could be undefined. And I was so happy to find this. We turned it on in our codebase. It found the error in the place that we actually had an error and then found a few others that I think probably had errored at some times. But it was just one of those for me very nice things to be able to dial up the strictness and enforce correctness within our codebase, and so I was very happy about it. Other folks may say that seems like too much work. And, you know, I get that, I get that take. I'm definitely on the side of I'm willing to go through the effort to have enforced correctness, but you know, that's a choice. STEPH: Yeah, that's thoughtful. I like that, how you said you can dial up the strictness so then as you are introducing TypeScript, then people have that option. There is an argument there in the back of my head that's like, well, if you're introducing types, then you want to start more strict because then you're just creating problems for yourself down the road. But I also understand that that can make things very difficult to then introduce it to teams in existing codebases. So that seems like a really nice addition where then people can say, "Yeah, no, I really want the strictness. This is why I'm here," and then they can turn that on. CHRIS: So TypeScript in the configuration has strict mode, so you say strict true. And that is a moving target with each new version of TypeScript. But it's their sort of [inaudible 28:14] set of things that are part of strict, but apparently, this one's not in it. So now I'm like, wait, can I have a stricter? Can I have a strictest option? Can I have dial it to 11, please? [laughs] Really rough me up and make sure my code is correct. But it is the sort of thing like when we turn any of these on; it will find things in our codebase. Some of them, we have to appease the compiler even though we know the code to be correct. But the code is not provably correct as it sits in our file. So I am, again, happy to make that exchange. And I like that TypeScript as a project gives us configurability. But again, I am on team where's the strictest button? I would like to push that as hard as I can and live that life. STEPH: Yeah, I like that phrasing that you just said about provably correct. That's nice. CHRIS: That's the world I want to live in, everything you own in the box to the left, which is probably correct. STEPH: [laughs] That's how that song goes. CHRIS: Yeah. This is a reference to move errors to the left, which I think I've referenced before. But now that I'm just referencing Beyoncé and not the actual article, it's probably worth referencing the article, but the idea of, like, if a user hits an error, that's not great. So let's move it back to QA, that's a little further to the left in sort of the timeline. But what if we could move it to an automated test in CI? But what if we could move it into your editor? What if we could move it even further to the left? And so, a type system tends to be sort of very far ratcheted up to the left. It's as early as possible that you can catch these. So again, to reference Beyoncé, everything you own in a box to the left. STEPH: [singing] Everything you own in the box to the left. CHRIS: Thank you for doing the needful work there. STEPH: [laughs] Mid-roll Ad And now a quick break to hear from today's sponsor, Studio 3T. When you're developing applications, it can often be a chore to work with your underlying data. Studio 3T equips you with a complete set of tools to work with MongoDB data. From building queries with drag and drop, to creating complex aggregation pipelines; Studio 3T makes it easy. And now, there's Studio 3T Free, a free edition of Studio 3T, which delivers an essential core of tools. This means you can get started, for free, with Studio 3T Free, and when you're ready, you can upgrade and enjoy even more features through Studio 3T Pro and Studio 3T Ultimate. The different editions unlock more tools and additional integrations with MongoDB, SQL, Oracle, and Sybase. You can start today by downloading Studio 3T Free, which also includes a 30-day free trial of all the features of Studio 3T Ultimate, so you can try out some of the enterprise features as well. No credit card required. To start your trial, head to studio3t.com/free that's studio3t.com/free. STEPH: I have a question for you that I'd really love to get your opinion on because I myself I'm waffling back and forth where someone brought up some really great points about a concern or just a question they had brought up around testing and i18n specifically. And I agree with the things that they're saying, but yet, there's also a part of me that doesn't, and so I'm Stephanie divided. And so, I'm trying to figure out where I stand on this. So let me dive in and give you some context; I'm going to share the statement/question that they had asked. So here we go. "One of my priorities has been I should be able to review a test without having to reference any other code. References to i18n means that I have to go over to YAML and make sure the right keys have the right values, and that seems error-prone. In some cases, a lack of a hit in the YAML defers to defaults. If the intent is to override the name of model attribute and error messages and it is coded incorrectly, the code fails silently without translating and uses the humanized attribute name, and that would go undetected. If libraries change structure, it might also fail silently as well, so to me, the only failsafe way is to be fully explicit in test." So this goes with the idea that if you're writing tests and then you're testing text, but it's on the screen or perhaps an email, that you're actually going to assert against that string that is shown to the user instead of referencing the i18n keys. And then that also backs up this person's idea that you really want to not have to jump around. If you're reading a test, everything you really need to know about that test should live very close by. And I really agree with that initial statement; I want everything that's very close to the test, especially if it's anywhere in that expectation line, I really want it close, so I can understand what's the expectation, what's under test, what are the inputs, what's the expected outcome. So I wholeheartedly support that idea. But yet, I am in the camp that I then will use YAML keys instead of providing that exact string because I do look at i18n as a helpful abstraction, and I want to trust that i18n is doing its job. And so that way, I don't have to provide that string that's there because then we're also choosing, okay, well, which language are we going to always use for our test? So this is the part where I feel divided. So I'm going to walk you through some of the reasons that I really support this idea and other reasons that I still use the i18n keys and then get your take on it. So there is a part of me that when I'm using the i18n YAML keys, it does make me sad because it reduces the readability in tests. Sometimes the keys are really well named where maybe it's a mailer.welcomemessage. And I'm like, okay, I understand the gist. I don't need to go see the actual string. I also think they highlighted a really good use case where if you're overriding behavior and it could default to something else, your test is still going to pass, and you don't actually know. So I could see the use case there where if you are overriding, then you want to be explicit about the string that you expect back. I also think there are some i18n messages that are fairly complex, and where then I really would like to see the string. So if you are formatting a date or a time or you're passing in just a lot of variables, then there's a chance that I do want to see how did that actually get generated for the person who's going to be reading it versus just maybe it's garbage text that came out? And I want to validate that the message that we think we're crafting is actually the one that the user is going to see. The case against actually being explicit, my biggest one is because then I do see i18n as a helpful abstraction. And I want to trust this abstraction that it's doing its job and it's doing it well. Because then if I do use explicit strings, it makes me sad if I change text from like hello to welcome, and now I have a failing test. I don't like that idea either. So I'm torn between these two worlds of it is very nice to have everything that you need in a test to be able to understand what is the expectation, but then I also lean into this abstraction and reference the i18n keys. So, Chris, with all of that, that was a bit of a whirlwind, [laughs] what are your thoughts? How do you test this stuff? CHRIS: Honestly, I'm surprised that you've got that much division in your own answer because for me, this is very obvious there's one...no, I'm kidding. This is obviously complicated. Similar to you, I think I'm going to have to give a grab bag of answers because I don't have a singular thought of like it is concretely this or that. I tend to go for explicit strings and tests all the way to...so like the readability of a test, and the conciseness of a test is interesting. I will often see developers extract. Say they're creating a user with a specific email, and then they log in with that email later, and then they expect something else. And so the email is referenced a few times, and they'll extract that into a variable called email. And I personally will tend to not do that. I will inline the literal string like user@example.com, and I'll do it in a few places. And I'm fine with that duplication because I like the readability of any given line that you're reading. So I will make that trade-off within tests. This is the thing I think we've talked about before, but the idea of DRY in tests is like I want to be careful applying that idea, Don't Repeat Yourself, to break apart the acronym. Those abstractions I will use them less than tests. And so I want the explicitness, I want the readability, I want to tell a little story, all of that feels true. That said, to flip it around, one of the things that I'm hearing...so I think I'm hearing a part of this that is around well, we can fail silently because we fail symmetrically in both the implementation and our test. Then an assertion may actually match even though it's matching on a fallback. I think that's a configurable thing. I would actually want my test to raise if I'm referencing an i18n key that is not defined. Now, granted, that's different for languages. And maybe this becomes a more complex story of like in production; in a different locale, it will fail because we don't have 100% parity across all our locale files. But fundamentally, I want to make sure that at least exists in our base, which I think typically would be en-US as the locale. I want to make sure all keys are looked up and found, and it's an error otherwise in our test. So that's a feeling. But am I misunderstanding that part of the story or how that configuration typically works? STEPH: No, I think you've got it. But just to make sure we're on the same page, so if you reference a key that doesn't exist, then it is going to fail. So at least you have your test failure is going to let you know that you've referenced something that doesn't exist. But if you are referencing, like if you want to override the defaults that Rails or i18n has provided for a model and say for an error message, if you reference that, but you want to override it, but then you've forgotten, that does exist. So you're not going to get the failure; you're going to get a different message. So it's probably not a terrible experience for the user. It's not going to crash. They're going to see something, but they're not going to see the custom message that you intended them to see. CHRIS: Gotcha. Okay, well, just to name it, the thing that I was describing, I don't know that that would be the configuration for every system. So I would strongly encourage any system where i18n just has a singular behavior which is we fall back to the key. I want my test to absolutely tell me if that's happening. And that should be a failure of the test. But to the discoverability documentation bit, I do wonder if tooling can actually help answer the question. And as I was describing the wonderful experience I had on GitHub the other day, viewing code as just static characters in a file is both true and also, I think increasingly, a limited view of it. We have editors, and we have code hosting tools that can understand semantically our code a little bit better. There's got to be like 20 Different VS Code plugins that, when you hover on an i18n reference, it will do the lookup for you. That feels like a thing that exists, and if it doesn't, well, now I've nerd-sniped myself, and I got a weekend project. JK, I'm definitely not building that this weekend. But that feels like can we use that to solve this? Maybe not. But that's just another thought of where we have these limitations where it's static, like those abstractions can be useful. But if we can very quickly dereference them, then the cost of the abstraction or that separation becomes smaller, and so the pain is reduced. And I wonder if that's a way to sort of offset it. STEPH: If I can poke at that a little bit more, because I think you're touching on something that I haven't expressed or thought through explicitly, but it's the idea of, like, why do I like the abstraction? What is it that's drawing me towards using these keys? And I think it's because most of the cases, I don't care. I don't care what the string is, and so that feels nice. Like, I understand that, yes, we're referencing something. If that key didn't exist, I'm going to see a failure. So I know that there's text there, and that's why I do lean into referencing the keys instead of the text because it feels good to not have to care about that stuff. And if we do make changes to the text, then it suddenly doesn't fail, and then I have to go update a test because we added a period or added a comma. I think that's the path of more sadness for me. And my goal is always a path of least sadness. So I think that's why I lean into it [laughs], I'm guessing. Is that why you lean into it as well? Or what do you like about referencing the keys over the explicit text? CHRIS: No, I think I share your inclination there, and the reason that you're in favor of it, and I think the consistency like if we're going to use i18n, then we should lean in because it's a non-trivial thing to do like porting to i18n projects, and they're tricky. Getting it right from the first step is also tricky. If you're going to do it, then let's lean in, and thus let's use that abstraction overall. But yeah, same ideas as you. STEPH: Cool. I think that helps validate where I'm at in terms of how I rationalize about this where ultimately, I do like leaning into that abstraction. And as you'd mentioned, some of those porting projects, I haven't been on one specifically, but I've seen that they are a lot of work. And so, if we have that in our system, then we want to continue to use it. It does reduce some of the readability. Like you said, maybe there's a VS Code plugin or some way that then we can help people be able to see if they want that full context in the test and not have to jump over to YAML. But yeah, otherwise, unless it's overriding default behavior or complex, then that's what I'm going to go with is with the keys. But I really appreciate this person's very thoughtful question and approach to testing because, normally or typically, I fully agree with I want full context in the test. And this one was one of those outliers that came up for me, and I had to really think through all the feelings and the reasons that I have for those feelings. On that note, shall we wrap up? CHRIS: Let's wrap up. The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeee!!!!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

The Bike Shed
332: Ludacris Speed

The Bike Shed

Play Episode Listen Later Apr 5, 2022 39:28


Chris is back from vacation and gives hiring and onboarding updates. Steph has an update about the CI slowdown and scaling CI. They tackle a listener question regarding having some fear around potential merge conflicts. This episode is brought to you by ScoutAPM (https://scoutapm.com/bikeshed). Give Scout a try for free today and Scout will donate $5 to the open source project of your choice when you deploy. Deckset (https://www.deckset.com/) parallel_tests (https://github.com/grosser/parallel_tests) paralleltests - important line that may alter the `groupby` strategy (https://github.com/grosser/parallel_tests/blob/9bc92338e2668ca4c2df81ba79a38759fcee2300/lib/parallel_tests/cli.rb#L305) KnapsackPro (https://knapsackpro.com/) rspec-queue (https://github.com/conversation/rspec-queue) Vim Conflicted Overview (https://github.com/christoomey/vim-conflicted#overview) Mastering Git Course on Upcase (https://thoughtbot.com/upcase/mastering-git) Git Object Model (https://thoughtbot.com/upcase/videos/git-object-model) Git Object Model Operations (https://thoughtbot.com/upcase/videos/git-object-model-operations) The Opportunity Will Find You (https://thoughtbot.com/blog/the-opportunity-will-find-you) This episode is brought to you by Studio 3T (https://studio3t.com/free). Try Studio 3T's full suite of features for 30 days, no payment details needed. Become a Sponsor (https://thoughtbot.com/sponsorship) of The Bike Shed! Transcript: CHRIS: Golden roads are golden. STEPH: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Steph Viccari. CHRIS: And I'm Chris Toomey. STEPH: And together, we're here to share a bit of what we've learned along the way. Oh, I also have a new intro that I want to try out. This is thanks to Irmela from Twitter, where it's good morning and hooray; today is Bike Shed day. They technically said Tuesday, but we don't record on Tuesdays. So today is Bike Shed day, so happy Bike Shed day. And hey, Chris, what's new in your world? CHRIS: What is new in my world? Yeah, I loved when I saw that tweet come out. It really warmed my heart. So Tuesday, in theory, is Bike Shed day, but for you and I, Friday is Bike Shed day. It's confusing breaking the fourth wall, as I so often do. But yeah, what's new in my world? I'm back from vacation, which is the thing that I did. For listeners, well, I have been absent the previous week related to vacation and all those sorts of things. But I did what we're going to describe as a not smart thing. It wasn't intentional. The world just kind of conspired in this way. But I had two separate vacation islands that existed in my mind, and then they both kind of congealed, but as they did that, they moved towards each other, but they didn't connect. And so what I ended up with was two weeks back to back where I was out on Thursday and Friday of one week, and then I was back for Monday and Tuesday. And then I was out for Wednesday, Thursday, Friday of the following week. Protip: that's a terrible idea. It's just not enough time to sort of catch up. The whole of it was like the ramp-up to vacation and then the noise of vacation, then getting back and being like, oh, there are so many emails. Let me try and catch up on them. But also, on the very positive side, we had a new hire join the team, and so most of my focus on the days that I was in the office was around getting that new person comfortable on the team, onboarding, spending as much time as possible with them. And so, all total, it was an adventure. And again, I would strongly recommend against this. The world just kind of conspired, and suddenly these three different forces in my life came together. And this was just the shape of things. But yeah, I went on vacation, and it was great. The vacation part was great. STEPH: I will take your advice. So next time I have like two segments of PTO, I'm just going to stitch them together and just go ahead and take that whole intermittent time off. CHRIS: That probably would have been better. Again, someone new joining the team, it was very important to me to get some time with them early on, and so I opted not to do that. But yeah, the attempt to catch up in between was a completely lost effort, I would say. But I think I'm mostly caught up now, having been back in the office for about a week, so yeah. But let's see, what else has been up in my world? It's actually been a while since you and I have chatted based on the various timing and schedules and the nonsense vacation schedule that I had that you so kindly accommodated across a couple of weeks. Let's see, hiring and onboarding; the hiring went really well. We talked about that a bunch of weeks back. But now we're in the onboarding phase. And so next week will be the first week that all four of us on the engineering team are in the office together for the full week. I'm super excited to experience that. We've had different portions of it, with me being on vacation and other folks being on vacation. But now, for the first time, we're really going to feel what it's like as this team. And we're going to have our first retro as a group and all those sorts of things, so I'm very excited to do that. And thus far, all of the interactions that we've had have been really wonderful as a team. And so now it'll be the first time we're just bringing all of those various pieces together. STEPH: I just have to clarify; you said all of y'all in the office together. Do you still mean remotely? CHRIS: Oh, yes, yes, I just mean not on vacation, all present and accounted for on the internet. Remote is another interesting facet of what we're doing here and trying to figure out how to navigate that, particularly where there are some folks that are closer and can potentially get together in the city, that sort of thing, and then folks that are truly remote and making sure that we're...I'm very much of the opinion if we have anyone that's remote, we are remote team, and we must embrace async communication and really lean into that. And I think the benefits of async communication as its own consideration are so worth it. And it's one of those things that's hard to do. It requires careful, intentional thought. It requires more purposeful communication. But I think there are a lot of good things that fall out of that. It's similar to TDD in that way in my mind, like, it's not easy. It's actually quite difficult. But all the effort that I put into trying to learn how to do that has made me a better developer, I think, on all the various fronts. And I think similarly, async communication I believe in as a tool to force just better communication. And so I'm a big believer in it, and I've found a ton of benefit in remote that I'm also a big believer in that now. I, like everyone else, was forced into it as the world was, but I've really come to enjoy it a lot. And so yeah, so, no, not physically in the office, to answer your very short question with a long rambling aside. STEPH: [laughs] I like that comparison. I hadn't thought about it in that way but comparing that thoughtfulness and helpfulness of async communication and then also to TDD, where it's not easy, but the payoff is so worth it, the upfront cost of it. That is something that at thoughtbot, we've had conversations around where there are folks that really value...they want to be around people. They get energy from people, and so they want that option to be able to rent a WeWork space and maybe get together with a colleague once or twice a week, and that was supported by thoughtbot. But we also wanted to express well, if you are together, do treat everything still as a remote work environment. So let's say if you and your colleagues are on a project, but then there's a third person on that project that's remote, you still need to act like everything's remote to make sure that everyone else is still getting to participate and hear everything and be part of the conversation. So just keeping that in mind that yes, we want to support you doing your best work, and if that's around people, that's wonderful. But we are still remote-first, and communication needs to be in that fashion. Well, that's super exciting that you'll have all of the team together. That sounds like it will be wonderful to hear about and then also retros and meetings, and yeah, it sounds like you've got a fun week ahead. CHRIS: Indeed. I'm super excited to see what sort of new things come out of the new voices on the team and practices that each of the individuals have experienced at other companies that we can now fold together. The work that we've done so far has been very much inspired by thoughtbot ideas, and approaches, and workflows, and processes because that's what I brought to the table. But I'm super excited to bring in more voices and see what of that 100% stays on versus does anything change? Do we get entirely new things? So yeah, very excited about all of that. But to revisit a topic that we've talked about in the past, this week is catching up from vacation, so there's a certain amount that will constrain my work. But this was definitely another week of I did not do much coding. I'm trying to think if I did any coding this week. It's possible that the answer is no. The fact that I don't even know the answer to that is an interesting one. I still have in my mind the desire to get back to it, and I think I will. But there's so much other stuff to do. Recently, this week, there's been a lot of vendor selection and contract negotiation, which is an interesting facet of the work, but just trying to figure out, oh, we need platforms to do X, Y, and Z. And it turns out they're wildly costly and have long sales cycles. And how do you go through that, and how do you make sure that we're getting the right thing? And so that's been a big part of my work. Hiring and onboarding, again, has been a big part of it. There's also some amount of communicating back to the broader team - what are we doing? What is the product organization or the engineering team delivering? And so I'm okay at presentations, I think. I'm comfortable with giving presentations. The thing that I struggle with is finding the optimization point in preparation. I will, of my own accord, over-prepare. And that may sound a little bit like, oh, what's my greatest weakness? That I care too much. But I mean it sincerely as like, I would love to find that right amount of like, it's like an hour of preparation for a 15-minute presentation to the team. That's the right ratio. And I just hit that on the head, and it's great. But whenever I know that I need to give a larger presentation, it will distract me. And it's work that can expand to fill whatever time you give it, and so trying to thread that needle is a tricky one for me. STEPH: Yeah, I'm with you. Presentations, for me, they're one of those things that it's very stressful, anxiety-inducing; all the prep feels distracting from some of the other work that I want to do. Or maybe I'm excited about the presentation, and that is the work that I want to do. But it's not until it's done that then I'm like, oh, that was fun. That went well. This was great. It's not until after that then I feel good about it. So the lead-up to it is very stressful. And so if you can optimize that to say, well, I know exactly what this group needs, where I can cut corners, where I have to go into details, that sounds incredibly valuable. I'm curious, so this is probably a bad idea, but it's the only way I really know how to find those boundaries is you got to experiment and tweak a little bit and let yourself fail a little bit or just be very explicit with folks about this is what the presentation is, if you expected something else, let me know. Or here's what I've got, have someone to bounce ideas off of. But there's such a nicety if you can find that I'm going to try failing just a little bit and get some feedback. Or maybe it's not failing at all, but you are testing that boundary to find out did this work, or should I put more effort into this? I'm curious, do you have thoughts on that? How you're going to find that right optimization level? CHRIS: Not as specific to truly honing in on whatever the correct number is. The thing that I've been doing is I...this will sound complicated, but I wait until the last minute but a specific version of the last minute. So at most, I start working on it an hour and a half before the meeting. And these are, again, not particularly large presentations, and it's a recurring sort of thing. So it's sort of engineering talking about the work that we've done recently and trying to find the right level of detail and whatnot, so giving myself a smaller time window. I think that's enough time to tell the story and to find a meaningful way to tell the story and grab the screenshots and all of that, but it's constrained so that I don't over-optimize, over-edit, overthink. I'm using Deckset, which is a presentation tool that starts from a Markdown file. So it's just a Markdown file that I'm editing. That's great; that works really well. I do not twiddle with fonts. There's one theme that I use. It is white background with black text. That's it. And I think I've given myself deep permission to be the CTO that has a white background with black text and no transitions. I don't even go into presentation mode for it. I'm literally showing the UI of Deckset, and then just hitting the arrow to move between them. But the Chrome and the drop-down menu at the top is still visible because I want to see people's faces as I'm presenting. And I haven't figured out how to do that correctly on my computer. So I'm just presenting the window of Deckset. And I'm like, I have given myself permission to do all of those things, and that has been super helpful, actually. So that's a version of me negotiating what this means. Where I do invest the effort is trying to enumerate all of the things and then understand what is the story that I'm telling around the things and how do I get the message right for the collective audience? So, for a developer team, I would say much more nuanced technical things, for marketing folks, it would be at this end of the spectrum. I do lean on the old idea of, like, let us talk about it in the mindset of the user, so it's very much user-centric, but then some of the things that we're doing are important but invisible to the users. They're part of how we broadly build the platform that we need to, but they're completely invisible to users. And so, how do I then tell that story still with ideally a user-centric point of view? So that's where I do invest the time, and I give myself complete freedom to just grab screenshots, put black text on a white background, and then talk over it. STEPH: I love it. Because you made this comparison earlier, so now I'm thinking of a comparison of like TDD-driven presentations where it's like, what's the end goal? What's the assertion? What's the outcome that I want? And then backfilling from there. Or, in your case, you're talking about what's the story that I need to tell? What's the takeaway that I want people to have? So then you start there, and then you figure out what's the supplemental information that you need to provide to then get there. And the fact that you don't twiddle with fonts and all that stuff, I think you're already really on your way [chuckles] in terms of finding that right optimization of I need to present a clear and helpful message but not sink too much time into this CHRIS: Black text on a white background is very clear. So... STEPH: [laughs] If there are any designers listening to this, they might just be cringing to this conversation right now. [laughs] CHRIS: I actually wonder about what the...I know that dark mode is a thing that lots of folks care about. I'm thinking about the accessibility affordance of it now. I'm actually thinking through it now that I said it somewhat flippantly. I actually don't know what I'm talking about, but it was easy, and it wasn't a choice that I allowed myself to think about. So there we are. Mid-roll Ad Hi, friends, and now a quick break to hear from today's sponsor, Scout APM. Scout APM is an application performance monitoring tool that's designed to help developers find and fix performance issues quickly. With an intuitive user interface, Scout will tie bottlenecks to source code so you can quickly pinpoint and resolve performance abnormalities like N+1 queries, slow database queries, and memory bloat. Scout also recently implemented external service monitoring, adding even more granularity when it comes to HTTP requests and API calls. So give Scout a try today with a free 14-day trial and experience first-hand why developers worldwide call Scout their best friend. And as an added bonus for Bike Shed listeners, Scout will donate $5 to the open-source project of your choice when you deploy. To learn more, visit scoutapm.com/bikeshed. That's scoutapm.com/bikeshed. STEPH: In my personal world, so Tim and I are moving. We're on the move. We are transitioning from South Carolina to North Carolina. So I think I may have shared a bit of this news, but Tim has acquired his first software developer job, which is just phenomenal. It is in North Carolina. He does need to be there in person for it. So we are currently selling our South Carolina house and then moving. It's not too far. It's like three and a half hours away to where we're moving in North Carolina because we're already pretty far in North and South Carolina. So yeah, there's always another box that needs to be packed. And there's always just something else that you forget, another thing that you want to take to Goodwill or try to give to a neighbor. It's a good way to purge. I will definitely say that every time you move, it's a good time to get rid of things. CHRIS: That is a very cup half-full point of view on it, but yeah, it feels true. STEPH: [laughs] It's true. I'm a very cup half-full person. For more technical news, for more client stuff that I've been working on, so I think the last time we chatted, I was sharing that we had this mysterious CI slowdown where we were going from CI builds taking around 25 minutes to spiking to 35, sometimes 45 minutes, and I have an update there. So we found out some really great things, and we have gotten it back down to probably more about 23 minutes is where the CI is running currently. As for the actual who done it, like what caused this specific slowdown, we got to a point where we were like, we're doing so much investigative work to understand exactly what caused this that it felt less helpful because at the end of the day, we really just wanted to address the issue. And so solving the mystery of exactly what caused this started to feel less and less meaningful because we're like, well, we want to improve this anyways. So even if we found that one line or something that happened that caused this, we want a bigger solution to this type of problem because then this could happen again like, someone else maybe adds one line or something happens, and things get thrown off balance, and then suddenly, we have a slowdown, and that just takes too long to investigate. So I don't have a concrete who done it answer for the slowdown. But we've learned a couple of things; one of the things that we learned is we're using parallel_tests to then split our tests across all of the CPUs that are then running the RSpec test. And we realized that we weren't actually splitting tests based on runtime data. So there are a couple of ways that paralleltests will let you divvy up your test, and two of those ways one is file size. So you can split the files based on the size of the file, or you can use info from the runtime log. So then paralleltests can be a little bit more intelligent about like, well, I know how long these files take, so I'm going to split it based on that versus just the size of the file. And we realized that we were defaulting and using the file size instead of the runtime even though we all thought we were using runtime. And the reason for this took a bit of source code diving because looking at the README for paralleltests; it looked like as long as we're passing in a file to the runtime log path, then paralleltests is going to use that runtime data. But then there's some sneaky-sneaky in there that I'll actually link to in the show notes in case anybody's interested. But if you are setting a particular flag and don't pass in another flag, then paralleltests is going to be like, cool, I'm going to portion out your test based on file size instead of the runtime. So we fixed that, or we updated that, and that has had a significant improvement for the test being split out more evenly. So we didn't have a CPU that was taking 25 minutes while the next CPU was only taking like 17 minutes. And paralleltests also provides some really helpful data that because we have that runtime log file, we could tell how long each CPU is running and how they're getting split. So the past couple of weeks, it's heavy measure, measure, measure, take all the data, create lots of graphs, understand what's happening, and then look for ways to then fix it. So figuring out how these files or how the tests were being distributed across, we had a number of graphs that were just showing us what's actually happening. So then we could track the improvement, so that was really nice. It was the measure twice and change something once [laughs], and then we got to see the benefit from it. For scaling the CI, so we are looking on adding more machines to then process tests. That has been really interesting because we're at the point where we are adding more machines, but if we add more machines, we're not going to speed up how quickly our CI processes everything. Because we are splitting tests based on file size and not by examples, we're always going to have this effect of a tentpole. So if we have a file that takes 10 minutes, that's the fastest we're ever going to get. So Joël and I are in discussions right now of where we still really want to understand what's the fastest we can achieve just by adding another machine or two versus are we at the point that, okay, scaling horizontally and adding more machines has been helpful, but we have reached the breaking point where we actually need to divvy out the tests at a smaller scale and have a queue approach? So then that way, we can really harness the power of then we don't have one file that takes 10 minutes, and we don't have to care either. So if somebody adds a test to a file and suddenly a file goes from 12 minutes to like...well, hopefully, they added more than one test. [laughs] But let's say it goes from 10 minutes to 15 minutes; we don't want to have to manage that and understand that there's a tentpole. We just want to be able to divvy out all the examples and then have a queue approach. That's probably going to be MVP two of this, but we're still waiting that out. But it's just been really interesting to realize that scaling horizontally really only takes you so far. Like, we've added one machine, maybe one more, so then we'll have three total. And then it's like, okay, that's great, but now we need to actually address this other bigger problem. CHRIS: I know we've talked about this in previous episodes, but I'm super interested to hear as you progress into the queue approach because that's something that's been top of mind for me for a while. I don't know if we've talked about it before specifically, but Knapsack Pro is the one thing that I'm available as a service that does this. Do you have other tools that you're looking at for that, or is this still in the exploratory phase? STEPH: Knapsack is still a top contender. There's also RSpec Queue; that's another one that we have in mind. Unfortunately, I really wish paralleltests let us do this, but paralleltests just doesn't quite offer that feature. And someone in the team, I think, even reached out to the maintainer of paralleltests, and they were like, "Yep, you're totally right. We're actually more focused in making sure that this works for everybody versus has specific features." And they gave a really nice thoughtful response, which we appreciated, so at least we could confirm that paralleltests won't do exactly the thing that we need. So yeah, RSpec Queue, Knapsack, I think those are the top two that I'm familiar with. CHRIS: Gotcha. I don't know if I've seen RSpec Queue before. I'm intrigued. So actually, an interesting thing happened. While I was away on vacation, one of the folks who just joined the team as one of their first steps joining the team, noticed that our CircleCI config wasn't actually taking advantage of the parallelism that we had configured; that's on me. I turned on parallelism and then never did anything with it, which is a complete waste. And so I was super happy to come back and saw that CI, which had been creeping up to six or seven minutes, had suddenly dropped back down to two to three minutes sort of thing. I was like, this is amazing. But now I'm at the point where our RSpec suite is spreading across the different, I think, it's like four different cores that we have available, but it's not doing it as efficiently as we would like. So I'm like, oh, okay, can we dial it up to 11? But I'm intrigued; I've only looked very much in passing at RSpec Queue literally now that you've mentioned it. But Knapsack Pro exists as a different service. And so, as far as I understand, the agent that's running is going to communicate and say, "Give me another test. Give me another test." But there needs to be some external process running and managing that queue. Does RSpec Queue do that? Somebody owns the queue, right? Who owns it? Do you understand how that works? STEPH: So I was definitely familiar with this. If you'd asked me a couple of weeks ago, when I was diving heavily into the queue work before then, we transitioned more into focusing on then adding new machines; I was very up to speed on this. So I may get a couple of things wrong, but my understanding is that RSpec Queue, you're going to manage your own queue. So you bring in the gem and then use something like Redis, so then you are in charge of that. And with Knapsack, then you are using their service to manage that queue. And then they have found ways to optimize around what if you can't reach their API or something; their service is down? And making sure that that doesn't impact your CI so then you can't still run your test just because you can't reach their queue somewhere. So that's my current understanding, RSpec Queue you own it, Knapsack they're going to own it. CHRIS: Gotcha. That makes sense. That about maps to what I was expecting, and so I wonder if I could use RSpec Queue. Now I'm going to have to go research that. But it's always nice to have new things to look at on this to go at ludicrous speed. That's what I'm going for. I want to get to ludicrous speed for our CI. STEPH: I like that name. I haven't heard of that speed. I feel like I have. I feel like you've dropped that before, [laughs] like you've used that. CHRIS: I don't know; quite possibly, I have. It's a Spaceball's reference. It's a throwback to days of old. STEPH: Well, then we may be investigating RSpec Queue together. Because yeah, Joël's and I goal for this week has been very much to figure out what's our boundaries with TeamCity? What are our boundaries with horizontal scaling? And I think we're both getting to that conclusion of like, okay, this has been good, it's helpful, but we really need to look into the queue stuff if we really want to see significant progress. Also, some of the stuff we're doing because we're pushing on it, we are manually splitting files. So if there's a file that has created this tentpole that's taking 10 minutes, but we know ideally most of the other files only take six minutes, then we are splitting that file, so then we have two spec files that are associated with the same class. And then using that as a way to say, okay, what would this look like? Let's say if this were better balanced. And that's also been pushing us in the direction of like, okay, this is fun, this is informative, but it's not sustainable. We don't want to have to keep worrying about splitting these files and doing this manually and pushing us towards that queue-based approach. MIDROLL AD: And now a quick break to hear from today's sponsor, Studio 3T. When you're developing applications, it can often be a chore to work with your underlying data. Studio 3T equips you with a complete set of tools to work with MongoDB data. From building queries with drag and drop, to creating complex aggregation pipelines; Studio 3T makes it easy. And now, there's Studio 3T Free, a free edition of Studio 3T which delivers an essential core of tools. This means you can get started, for free, with Studio 3T Free and when you're ready, you can upgrade and enjoy even more features through Studio 3T Pro and Studio 3T Ultimate. The different editions unlock more tools and additional integrations with Mongo DB, SQL, Oracle and Sybase. You can start today by downloading Studio 3T Free, which also includes a 30 day free trial of all the features of Studio 3T Ultimate, so you can try out some of the enterprise features as well. No credit card required. To start your trial head to studio3t dot com forward slash free. That's studio dot com forward slash free. But shifting gears just a bit, we have a listener question. So this person wrote in, "I have listened and loved your podcast for many years dreaming of getting a job with people half as thoughtful and intentional as you, and finally it happened. I have my first junior dev job, and my co-workers and bosses are all super awesome. Up until now, I've been flying solo. And in my new job, I've been finding it very unsettling to resolve merge conflicts. As careful as I am to comb through the conflict and contact the other developer if needed, I feel like I am covering my eyes and crossing my fingers whenever I select the resolve conflict button. Is there some type of process or checklist I could rely on? Is it normal to have such a high fear factor with a merge conflict? Any advice or maybe just a bit of been there felt that way...?" All right. So one, that's fabulous, congratulations on the new job. That's very exciting. I think I've voiced this many times, getting your first junior dev job is so hard, and so I'm so excited when it works out for people, and they get there. And then, for the merge conflict, I have thoughts. Chris, do you want to start? Shall I start? How are you feeling? CHRIS: Why don't you start? Well, actually, I'm going to add some pre-commentary, and then I think you should lead into our actual answer. But first, I just want to say a deep thank you to this listener for sending in the question. Again, we really love getting these questions. And also, thank you for the very kind words. To be clear, listener, if you're going to send in a question, you don't have to say very kind words, but they are really wonderful to hear and especially to hear if we had any part in helping this person feel more comfortable getting into that first dev role and having an idea of what maybe a good version of that could look like. Additionally, I really love the shape of this question because it gets into the people stuff and the tech stuff, so I'm super excited about this question. Actually, both Steph you and I responded very quickly to this one. And so it really did catch our attention because I think it crosses that boundary in an interesting way that I think is sort of The Bike Shed space in the world. But to that end, you did reply first in our email chain. So I think you should start, and then I'll follow on after that. STEPH: I should also check with you. Wait, so you don't have a filter on your email that's like kind words only to The Bike Shed, and then you filter out anything that's negative? CHRIS: I have a sentiment analysis, and if it's even neutral, it gets sent straight to the trash, only purely positive. No, constructive feedback is welcome too. We would love to hear that. Well, love is a strong word. We would accept it into our inboxes and then deal with it, but yeah. STEPH: [laughs] It will be tolerated. Must require at least three hearts in all emails; just kidding. [laughs] CHRIS: Are you kidding? I'm counting them now, and I see a lot of hearts in our emails. [laughter] STEPH: Merge conflicts. So is it normal to have such a high fear factor with a merge conflict? I'm going to say absolutely. Resolving a merge conflict can be really tricky and confusing. And I think; frankly, it's something that comes with just time and practice where then you start to feel more confident. As you're resolving these, you're going to feel more comfortable with understanding what's in the branch and the code changes that you're pulling in versus something that you need to keep on your side. So I think over time, that fear will subside. But I do think it's totally normal for that to be a very scary thing that then takes practice to become accustomed to it. As for if there is some type of process or checklist, I don't know of a particular checklist, but I do have a couple of ideas. So one of the things that I do is I will often push my code to whatever management system I'm using. So if I'm using GitHub, then I'm going to push up my branch because then, at least that way, someone has a copy of my work. So if I do something and I completely botch it locally, I know I can always reset to whatever it is that I pushed up to GitHub, so then that way, I have more freedom to make mistakes and then reset from there. So that is one idea is just put it somewhere that you know is safe, so that way you now have this comfortable sandbox to then make mistakes. The other one is run the test. So hopefully, the application that you're working with has tests that you can trust; if not, that could be another conversation. But if they do have tests, then you can run those, and then hopefully, that would let you know that if you have left something in, like maybe you left a syntax error, or maybe you removed some code that you shouldn't have because you weren't sure, then those tests are going to fail, and they'll let you know that something went wrong. And you can run those while you're still in the middle of that merge conflict as long as you've addressed like...well, no, if you haven't addressed syntax errors, that's still a time that you can run it, and it's going to let you know that you haven't caught all of the issues yet. So you don't have to wait till you're done to then go ahead and run that. A couple of other ideas, practice. So go ahead and create your own merge conflicts on purpose. So this is something that I think is really helpful because it will teach you, one, what causes a merge conflict? Because now you have to figure out how to create one, and then it will help you become comfortable because you're in a completely safe place where you have made up the issue, and now you're having to resolve that, so it'll help you become more confident in reading that merge conflict message. And then last but certainly not least, grab a buddy so if you are just feeling super nervous. Anytime I'm doing something that I just feel a little nervous about, then I just ask someone like, "Hey, would you look over my shoulder? Would you pair with me while I do this?" And I have found that's incredibly helpful because it eases some of my fear. I've got someone else that is also looking through this with me. But I also find it really helpful because then it encourages that person to be like, hey, if they're ever in a spot that they need to pair, I want them to know that they can also reach out to me and have that same buddy system. I guess that's my checklist. That's the one I would create. How about you, Chris? What do you think? CHRIS: Well, first, I just want to say that basically everything you said I 100% agree with, and purposely I think was great that you actually replied to the email first and that you're saying those things first because I think everything that you said is true and is foundational. And it's sort of the approach that I would definitely recommend taking as well. My answer, then adding on to that, has to do with how I've approached learning about this space in my own career. To name it, to answer the core question, is it reasonable to be scared of this? Yes, Git is confusing. Git is deeply confusing. I absolutely love Git. I have spent a lot of time trying to understand it, and in understanding it, I've come to love it. But it's only through deep effort that I've gotten to that place. And actually, the interface, the way that we work with Git on a day-to-day basis, particularly the command line is rough. I'm going to say, what does Git checkout do? Well, it does just about everything, it turns out. That command just does all of the stuff, and that's too much. It's, frankly, the UI for Git, specifically the command-line user interface; the commands that we run to manipulate the Git history are not super intuitive. But it turns out if you pop open the hood, the object model underneath the core way that Git stores your code is actually very simple. I find it's very easy to understand, but I, unfortunately, have found that I can't understand it without dropping down to that level. And so, in my own adventures, I kind of went deep on this topic a couple of years ago, and I created a Vim plugin because obviously, that's the best way to encapsulate your knowledge about Git, and so I created a plugin called Vim Conflicted. I don't necessarily recommend the plugin. It's fine if you want to use it. I don't do a great job of maintaining my plugins at this point, to be honest. But there was a weekend where I was trying to understand the world of Git and merge conflicts in particular, and it was really sort of fighting me. And as I started to understand it better, there's a little diagram that I drew on the README that I think is probably the most interesting artifact from it. But it's this idea that there are actually four files, four versions of a given file involved in any merge conflict. And that realization shifted my thinking a good amount. And then as I started to think about that, I was like, oh, okay, and then I want to see this version of it, and this version of it, and this combination, and the diff between these two, and that was super helpful for me. More generally, I also made a course on Upcase about Git as I tried to understand it better. And there are two particular videos from the middle of the course named the Git Object Model and Object Model Operations. And again, those two videos deal with popping the hood on Git, looking inside it, and what actually is happening to your code as you perform different Git operations. One of the wonderful things about Git is it is immutable. So you're never going to destroy your Git history if you've committed. So one of the rules that I have is just always be committing, never worry about committing. If you've committed, you can always get back to that version. You would have to try very hard to destroy committed code in Git. It's the things that you do when you haven't yet committed the code that are dangerous. So commit the code, like you said, Steph, push that up to GitHub, so you have a backup of it. You will have a backup locally as well, and that's a thing that you can come to be more comfortable with. But then, from there, there's actually a lot of room to experiment and play around because there's a ton of safety in the way that Git stores the code. You do have to know how to get at it, and that's the unfortunate and tricky part. But I think, again, to sort of summarize, yes, this is confusing. Your feelings are absolutely valid and totally grounded, but it is also knowable, is what I would say. And so, hopefully, there are a couple of breadcrumbs that we've laid there in how you might go about learning about it. But yeah, find a buddy, watch a video or two, and give it a try. This is definitely a thing that you can get there but totally reasonable that your first approximation is this is confusing because it sure is. STEPH: I often forget that Git has that local copy of my code, so I'm so glad you mentioned that. And then yeah, I saw when you linked to Vim Conflicted. The diagrams are great. I had not seen these before. So yeah, I highly recommend folks take a look at those because I found those very valuable. CHRIS: In that case, it's a white background, but I allowed myself to use some colors in the little images to help differentiate the different pieces. And it's an animated diagram, so it's really a high bar for me. [laughs] STEPH: So now the question is, did you go too far? Have you over-optimized? [laughs] CHRIS: I'm going to be honest; it was a weird weekend. STEPH: [laughs] Well, I don't think you've over-optimized. I do think it's wonderful. And I think this is definitely a reference that I'll keep in mind for folks whenever they're learning about merge conflicts or just want to get more knowledgeable about them. I think these diagrams are fabulous. CHRIS: Well, thanks. Yeah, I hope...they frankly were a labor of love, and the course is three and a half hours of me rambling about Git, so hopefully, it's useful to folks. If anything, it was super useful to me because my understanding of Git was deeply crystallized in making that course. But I do hope that it's useful to other folks. And particularly those two videos that I highlighted, I think are the ones that have been most impactful for me in terms of how I think about working with Git and getting comfortable with it. STEPH: Do you still receive emails every now and then from people, or maybe they are tweets from people that are like, "Hey, I watched one of your videos and found it really helpful." I feel like I still see that every now and then where people are just commenting on like, they watched some of the content that you created for Upcase a while back, and I think that's really cool. I'm curious if you still see that. CHRIS: I do, yeah, from time to time. It is absolutely wonderful whenever I hear that. Again, listener, do not feel the need to send me anything, but it is nice when I get them. STEPH: It does seem like I'm fishing for compliments now. [laughs] CHRIS: It does seem like that. So I want to be clear that's not what's going on here. But it is nice because I do actually forget that they're out there. But a lot of the stuff that I produced for Upcase, in particular, I tried to do more timeless stuff, so like the Vim content was really about how Vim works in a deep way. And the tmux course and the Upcase course...or the tmux course, the Git course. I look back at them, and a couple of little syntactic things have changed. But I'm still like, yeah, I agree with me from six years ago or whatever it was. Oh, that's a weird number to say, and I think is honest. It's fine. I'll just be over here. [laughs] STEPH: [laughs] That's helpful to hear, though, because that's always one of my fears in creating content. It's like, I don't know, it's okay if it's more opinionated and I change my mind and disagree with my past self. But it's more like, yeah, keeping up with is this still accurate? Is this still reflective of the times? And then having to keep that stuff updated. Anywho, that's a whole big thing, content creation. CHRIS: Content creation, but there's a parallel to it that many folks will not be creating content, and I think that's a very fine and good way to go about progressing on the internet. But there's a parallel to it in learning that I think is useful. I, at this point, will typically lean in if there is something in the SQL layer that is fighting me. I have never found effort spent trying to better understand the structured query language to be wasted time. Similarly, Git is one of those tools that is just so core to the workflow that it felt very worth it to me to spend a little bit of extra time to get to a deeper level of comfort with it, and I have not regretted one minute of that. Vim and tmux are pretty similar because they're such core tools for me. But React, I would not call myself a deep expert of React. I follow some of the changes that are happening but not as deeply, and I'm not as worried about it. And if I'm like, I don't know how to do this thing, should I spend two hours learning about it or not? With frameworks and tools that have not been part of my toolset for as long, I will spend less time on them. And I think that the courses that I produced on Upcase mirror that. They're the things that I'm like; I feel very true about these things versus other stuff. Maybe it was in a weekly iteration episode or something like that. But that very much mirrors how I think about learning as well. What are the things that I'm going to continually invest in versus what are the things that I'll sort of keep an eye on from a distance but not necessarily invest as much time in? STEPH: There's a particular article that you're making me think of as we're talking about content creation and, as you mentioned, finding the things that you always find value in investing in. There's a wonderful blog post that was recently posted on the thoughtbot blog by Matheus Richard, and it's called The Opportunity Will Find You. And it made me think a lot about what you're talking about, find the things that you're excited about, find the things that you think are a good investment and just go ahead and lean into it. And it's okay if maybe that's not the thing that you're using currently at your work, but if it's something that gets you excited, then go ahead and pursue that. So in this article, for example, Matheus uses the example of learning Rust, and that's something that he's very excited about and wants to learn more about. And then there's another one where he started looking into crafting interpreters. And then that has actually led to then some fruitful work around creating custom RuboCops because then he had more knowledge around how the code is being interpreted so then he could write custom RuboCops. So yeah, plus-one to finding the things that give you energy and joy and leaning into that and investing in it. And if you share it with the world, that's fabulous, and if you don't, then keep it for yourself and enjoy it, whatever makes you happy. On that note, shall we wrap up? CHRIS: Let's wrap up. The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeeee!!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

The Bike Shed
331: Git Down

The Bike Shed

Play Episode Listen Later Mar 22, 2022 29:28


Steph celebrates Utah's adoption day and Daylight Savings Time and troubleshoots a CI build time that had suddenly spiked for a client project using TeamCity. She also shares a minor update regarding the work that thoughtbot is doing to scale horizontally and add more machines quickly and efficiently to process more RSpec tests. Chris was alarmed by logs and unknown-unknowns and had some fun using Git down. Git bless his heart! This episode is brought to you by ScoutAPM (https://scoutapm.com/bikeshed). Give Scout a try for free today and Scout will donate $5 to the open source project of your choice when you deploy. TeamCity (https://www.jetbrains.com/teamcity/) lograge (https://github.com/roidrage/lograge) Cleaning up local git branches deleted on a remote (https://www.erikschierboom.com/2020/02/17/cleaning-up-local-git-branches-deleted-on-a-remote/) Become a Sponsor (https://thoughtbot.com/sponsorship) of The Bike Shed! Transcript: CHRIS: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Chris Toomey. STEPH: And I'm Steph Viccari. CHRIS: And together, we're here to share a bit of what we've learned along the way. So, Steph, what's new in your world? STEPH: Hey, Chris. Today is Utah's adoption day. So officially, one year ago, we adopted Utah. He's about a year and a half years old now because we got him when he was around the six-month mark. So Utah, aka Raptor, which is the nickname that you gave him, and aka UD [spelling] the cutie is his other nickname...which I've forgotten, why do you call him Raptor? Why is that a name? CHRIS: Because there's a Utah Raptor. STEPH: A person? [laughs] CHRIS: No, I think it was like the fossils were found in Utah. But the Utah Raptor is a type of dinosaur. And so when I heard Utah, my brain went to Raptor, and then I dropped the Utah sort of a Cockney rhyming slang sort of thing. Shout out to Matt Sumner real quick. But yeah, Raptor. STEPH: Cool. Cool. Cool. I'm so glad I asked. Now I know. I just accepted it when you called him Raptor. I was like, sure, he can be a Raptor. [laughs] CHRIS: I feel like that says a lot about me that you were just like, okay, why not? STEPH: [laughs] CHRIS: That's different and has no apparent connection to the actual name of the creature, but that's fine. I might be a nonsense person. STEPH: Or me for accepting it. You share a lot of nonsense, and I accept a lot of nonsense. That might be our dynamic. [laughs] So it works out. CHRIS: That just may be our dynamic. STEPH: That's why I'm always so nice with the good idea, bad idea, or even terrible. [laughs] CHRIS: You're like, it's all nonsense 100% of the time, but yeah. So Utah is one year into living with you folks. So that's lovely. STEPH: Yeah, and he's growing up so well. Oh, and I've been training him for one of his latest tricks. I'm very excited because it seems to be really sinking in. So every night, we take him out for his final bathroom potty but then before we go to bed. And one night, for some reason, I started singing The Final Countdown. [singing] It's the final countdown. But I started singing it's the final potty instead. So now, when it's time to go out for the bathroom late at night, I look at him, and I start singing. And I start singing [vocalization], and it's working. He's starting to recognize that when I started singing that tune, he's like, okay, and he gets up from his comfy spot, and we go outside. And it brings me a lot of joy. CHRIS: That is perhaps the best use of Pavlovian conditioning that I've ever heard of. Also, I really appreciate that you both mentioned the final countdown but then said just in case anyone is unfamiliar with the tune, let me hum a few bars. Thank you for doing the service there. STEPH: I have been singing so much this week. I don't know if Joël Quenneville, who I've been pairing with a lot, appreciates that. Sorry, Joël. But I have been singing so much. And I think that's post-vacation vibes. That's what vacation does for you. And it helps you get back into, you know, lots of singing or at least it does for me. Let's see, what else is going on this week? So this is the week that we have DST in the USA, so Daylight Savings Time, aka summertime, where we advance our clocks so everybody...although this is going to be late. So at this point, by the time people are hearing this, you're going to have already dealt with all those bugs that have crept up. But those are creeping up this week, where people are starting to notice a lot of those flaky specs that aren't technically flaky. They're actually breaking for real reasons because they were tested in a way that shows that they're not considering that daytime boundary. CHRIS: It's as if you spend some of your time fixing flaky specs that that's where your mind goes with DST. Because I'm going, to be honest, part of what you're doing right now is telling me that this is coming up, and I didn't know. I had forgotten about that, which is very exciting, except you lose an hour asleep for this one, right? Or is it that you gain? STEPH: We're going forward. Yeah, it's fall back and then spring forward. That's how I remember it. CHRIS: Worth it. I'll take the sunshine at night. STEPH: Yeah, it's supposed to be so we have more sunshine during the daylight hours. That's the reasoning for the nonsense, the headaches. On some more technical news, when I came back from vacation, we noticed that the CI build time has suddenly spiked for the client project where previously we were averaging, I'd say, around 25-26 minutes. There's definitely a range there. But that seems to be pretty consistent. And right now, builds are taking more about 35, sometimes upwards to 45 minutes. And so it's been a bit of who done it or what caused it adventure of figuring out why, what's causing the spike. And so Joël and I have been pairing heavily on that to investigate what's going on and learned a lot of features that TeamCity offers and just diving into this particular issue. One thing that brought me joy is by looking through all the builds that are taking place on TeamCity. As I noticed, there are a number of builds that are using the RSpec selective testing that I added where if you only change a test to then we're only going to run those tests instead of the whole suite. And it was one of those changes where I thought, okay, maybe someone's going to get use out of this. Joël and I will probably get use out of this. But I'm actually seeing it about one every ten build something like that. And I'm just like, oh, this is awesome. One, people are improving tests. That's amazing. And then two, that then they're benefiting especially while we have this spike going on. So that was a suggestion from you that I appreciate because that is paying dividends. And so that brought me a lot of joy while looking into this other issue, which we haven't resolved yet. We think it has something to do with how the tests are being balanced across all the different parallelized processes. And we think that there is an imbalance that has happened. And then that's what's really throwing things off. So we can see that one particular process is taking around 26-27 minutes, but then the next process that's highest in time is only taking 17 minutes. So it's like, why is there suddenly ten more minutes that's being attributed to one process? And why is that not getting spread out? So still looking into that. That's the mystery for this week. But that's mostly what's going on in my world. What's up in your world? CHRIS: What is up in my world? I'm going to say a quite alarming thing happened this week, which was we were investigating some changes, or we were investigating some behavior where the particular portion of the system ended up in the logs, just sort of combing through. And I happened to notice this one log line that...our logs tend to be somewhat verbose. They're JSON-structured log format. I've talked about the lograge setup that we use in the past, but there's a bunch. These are long lines of JSON-structured data. But this line that caught my eye was not. It was just some text, and it said, "Unreported event: and then some other texts." And I was like, ah, what? Who didn't report which to when? I did some digging, eventually figured out that this was Sentry. Sentry was logging that it had not reported an event to us. But had we not randomly happened upon this in the logs, which is sort of a random thing to see, we would have missed this, which is scary. I mean, it was missed for a little while. And so Sentry was not reporting certain events. We had made a change, particularly to Sentry's before_send configuration. So there's a way that you can do some amount of filtering client-side or client being, in this case, our Ruby app. So that's like the client-side of Sentry, and then there's their server backend. So that would, weirdly, that's the way the client-server work in this case. But the idea is you can do some proactive filtering of being like, you know what? Rather than sending a ton of noise...because we know there's this one error that we can't stop for reasons. It's a JavaScript Chrome extension that's getting embedded in the app. That doesn't mean anything; that's just noise. Rather than even sending those over to Sentry, let's proactively filter them out. before_send is a function within the Sentry SDK that allows you to do this. But it turns out if you raise an error in there, if you happen to have introduced something that doesn't cover all the possible edge cases, then Sentry will just not let you know and will log, interestingly, that they did not report the event. I'm going to throw it out there that I would love if Sentry were to say Sentry me...that's where I put something very bad happened, and you should look at it. And they're just like, well, something pretty darn bad happened. We'll log it. Supposedly, my understanding is before_send can be used to filter out like PII or other things like that. And so their failure mode is quiet intentionally. That's my understanding as to maybe why this is true. I wish there were configuration that said, no, please fail as loudly as humanly possible. But that was terrifying. STEPH: Yeah, absolutely. I'm going to piggyback on what you just said for a minute because I was also thinking earlier and related to the sudden spike in our CI builds where I was like, it would be really nice if there's...because I suspect there's one particular change that has caused this to happen. I don't know what it is yet, but that's just my suspicion. And it would be great if when that build ran, let's say that build went from an average of 25 minutes and suddenly we have a build that took 35 minutes if TeamCity had alerted us or if something more aggressive had to happen to say like, "Hey, your team..." or maybe it's just in the logs somewhere. Okay, not in the logs somewhere more visible on the build where it's like, "Hey, your build took an extra 10 minutes compared to the average, just letting you know. I don't have a diagnosis for you, but we're just letting you know." So yeah, plus-one to getting those types of alerts out to people and notifying us when there's an average that's not being met or when things aren't getting logged like you'd expect them to. CHRIS: As part of what we were doing in the logs...like how to get to that anomaly detection place is a really interesting question in my mind. And this is a case where we were in the logs, and we wanted to instrument more things. So we have a bunch of stuff right now that goes in. It's either a warn or error log level. And the error should be pretty rare because, ideally, those are going to Sentry instead, but we still want to keep an eye on them. But we introduced a new search within log entries, which is what we're using for logging aggregation and searching. And the idea was to group all warn-level messages and to group it on the message string. So ideally, what this allows us to do is say, "Oh, we've seen 200 instances in the past two days of this new warning that we didn't see before." The difficulty is, as a human, I would see unhandled error blah as one bucket of warning, or I might want to see it that way. I might want to group it on part of the message. So it becomes really hard to find the signal in the noise on these, but at least it was a start. We now have this little graph for both warning and error-level log messages that we can see are there any new anomalies that are occurring pretty regularly? But this, again, was just this weird edge case where we were lucky to catch it. But it was very scary that it was just throwing stuff away. So the universe might have been true that our error log did get a little quiet for a little while, which was nice, but it wasn't 100%. It wasn't like we were at 10 hours, an hour, and then we went to zero. It was like some, and then we went to a lower number because we were still getting some. We were only filtering out certain ones. But yeah, it's how do you know at runtime that the system is doing the thing? This is increasingly the question that I have in my mind. But yeah, so that was the thing. We fixed it. It's fixed now. I also set up an alert in log entries to say, "If you ever see this particular phrase again unhandled or unreported," then please tell me about that post-haste. So we've got that now. STEPH: That's perfect. That's what I was about to ask us if there's a way that you could add a filter or add a warning for that anomaly detection. So that sounds great. CHRIS: I've got that now because this became a known-unknown, but there are still the unknown-unknowns, and there are so many of them. And I can't know them is my understanding of how they work. I would love to know them. I would love to pin them down and be like, "Hey, what are you doing here?" Someday maybe. But anyway, that was the thing in my world. [laughs] It was fun. It was a great little time. What else is up in your world? STEPH: I feel like you can always judge the level of fun based on how high someone's voice goes. No, it was fun. It was great. It was fun. [laughter] CHRIS: I believe that is an accurate assessment, yes. STEPH: I've caught myself doing that. I'm like, my voice is extra high, so I don't think I really mean that when I'm using the word fun. [laughs] Mid-roll Ad Hi, friends, and now a quick break to hear from today's sponsor, Scout APM. Scout APM is an application performance monitoring tool that's designed to help developers find and fix performance issues quickly. With an intuitive user interface, Scout will tie bottlenecks to source code, so you can quickly pinpoint and resolve performance abnormalities like N+1 queries, slow database queries, and memory bloat. Scout also recently implemented external service monitoring, adding even more granularity when it comes to HTTP requests and API calls. So give Scout a try today with a free 14-day trial and experience first-hand why developers worldwide call Scout their best friend. And as an added bonus for Bike Shed listeners, Scout will donate $5 to the open-source project of your choice when you deploy. To learn more, visit scoutapm.com/bikeshed. That's scoutapm.com/bikeshed. I do have a small update that I can share regarding the work that we're doing to be able to scale horizontally. So we want to be able to add more machines quickly and easily so we can then process more RSpec tests. And we have discovered with TeamCity that we're pushing forward on that particular path because they have something called a composite build. And with a composite build, it's essentially your parent or your supervisor build. And then, from there, you can create other subsequent builds. So we can then say, all right, let's have multiple builds that then run the RSpec test, and then we can separate in that way. And right now, we're going about it in the hacky way because we just want a proof of concept. So we are saying specifically in this particular step, we want you to run spec models. And in this other process, we want you to run these particular tests just because we want to see how this works. And so far, the aggregation seemed great. So when you look at that composite parent build, it's showing you how each of those builds are doing. It's also reporting back the failures. It's even de-duping them. Because initially, we set it up where we were running the full test suite in parallel on both of these builds, [laughs] not what we wanted, fixed that. But it did highlight that it was de-duping the test failures. So that part was nice. So the UI seems great and seems quite very capable of doing this. Composite build seems to be the way that we can do this with TeamCity. But we're still diving into actually getting the metrics like, okay, how much is this actually going to speed us up? And what does this look like if we want to be able to scale up to say from 5 to 10 where we went from 5 machines to 10 machines? And that part doesn't feel graceful because then you have to go in and change the configuration and copy the configuration to then add a new build that then is going to process RSpec test. So other services like Buildkite make it very easy. I can't remember if it's like literally a slider or if it's a number that you enter. But you can say, "This is how many processes that I want to run," in which it would be a lot nicer for that actual scaling. Versus TeamCity, it feels far more manual and intentional where you then have to duplicate and add those settings. But it's a really good first step because, as we'd highlighted before, there's a lot of risk in moving over from an existing infrastructure to something totally new. So if we can have some wins with this approach and help out the team and reduce build time, then that gives us more grace period. So then we can assess, okay, do we really want to move over to Buildkite? What do we want to do next? What does this look like? And have further discussions. So that's a small update there. Next time I should have some more updates around actual data on how things are looking. CHRIS: Oh, cool. Yeah, I appreciate the update and definitely interested to hear how this continues to play out. This is a large project that you're undertaking and all the facets and whatnot, so yeah, super interested to hear the continued journey of the test build time reduction. Let's see, other news in my world. I've been exploring something that I'm intrigued by the idea. Let's go with that. [chuckles] That's going to be my start. I always start with these lead-ins that build things up too much. But I am finding a small tension in trying to just keep up with what the team is doing, which is a wonderful place to be. Our team is growing. We actually have someone new joining tomorrow, very exciting. But I'm trying to find the right version of I don't want to block things. I don't want all code review to have to go through me. But I do want to keep an eye on everything. I want to kind of know what we're doing collectively. And ideally, mostly, that's me being like, yep, that makes sense. We're doing that. I remember that, cool. Wait, what's this? And rarely, occasionally, there'll be a point where I'm like, oh, I want to intervene here. I want to have a conversation. I want to rethink how we're building this. And so it's moving from a place of any sort of blocking synchronous review or the necessity for that to ad hoc post-review sort of thing. And so the way that I'm trying to poke around with this, of course, I'm writing some code to do it because of me. So the two systems that we're using that seem most of interest are GitHub and Trello. And so it turns out GitHub has a wonderful search, and I can create a search that is parameterized like create a URL that jumps into a parameterized search saying, "Show me everything that was merged in the past X amount of time, " so I can say the past two days because I haven't checked it in two days. So I'll see all of the PRs that were merged, and some of them I'll have already reviewed. So I maybe could even filter further there. But for anything that I haven't seen, I'm like, oh, what was this? What was that? What was this other change? Similarly, on Trello, there's a way via the API to get all of the card update actions. And then I can filter down to say whenever a card was moved, which in our system that means...we're doing Kanban-style, so a card being moved from this column to that column that tells me that someone is progressing forward with some work. And then I can further filter down because, again, I don't really want to be blocking on this. I'm most interested in what have we done or completed in the most recent timeframe. And thus far, it's an interesting data set. And it's an interesting way to switch the problem around such that I'm not feeling...there was FOMO or organizational FOMO is perhaps how I would describe it of like, I want to try and keep an eye on stuff and make sure I'm responsive. But I'm now blocking, so I have to step away. But now I'm worried that I'm missing things. And so I'm trying to find that good middle spot. And this feels like an interesting exploration of that. STEPH: I'm intrigued when you mentioned the card moving over, so then you can tell things are progressing. And then you're answering the question of what did we do in this particular chunk of time? When you move stuff over, is there a clear sweep of we have finished this sprint, and then you have the date of that sprint at the top, and so then you essentially have a column that represents all the work that was done in that sprint? Is that an approach that you're using? Because that's the one that immediately came to mind for me when you're wondering what was accomplished during this week or two-week period? CHRIS: Interesting question. So we're not really doing sprints, or there are no real iterations. We're doing more of the I think Kanban is the way to describe it. But basically, we have a prioritized next up column. And then every day, I can say continuously, the work has the same shape, which is pick up the next most important thing, work on it, move it through the various columns. I did introduce in Trello just the idea of, like, here's a month, so we can see by month what we're doing, but that's too low granularity in my mind. I want to review it a month at a time. The whole point of this in my mind is to see stuff as it's happening vaguely in real-time but not requiring me to constantly be monitoring everything. So it gives me an opportunity at the end of the day to be like, what happened today? What do we do? But yeah, so there's no real sprint that I would couple this to because we're not really doing sprints. STEPH: Got it. Yeah, that gives me more context. I understand why you're then looking for ways as to how to answer that question of, like, what did we accomplish in this week or a particular time period? CHRIS: And to name it, this is not an intention on my part to be like, I need to control everything. I need to make all the decisions. I very much want to empower the team. And in my mind, this is actually a mechanism to empower the team. I want to give them more freedom and then have the opportunity occasionally to check back in and be like, oh, actually, there was some context that was missing here the way we did this. Let's actually unwind that, do it this other way for these reasons. But it gives me the ability to potentially have that conversation after the fact. We're trying very hard to have the tickets be as representative and complete, and well documented as possible. But that's very difficult to get to. And there are also things that I don't even know to mention. Again, I think the critical bit is this is not an attempt to make sure everything aligns with what I think; it's more I want to empower the team to move without me most of the time. And then, where there are things that potentially should have a small conversation or a redirection, then we have the ability to do that. And so, I'm trying to build that back into my workflow while basically loosening up my connection to the work in progress at any given point in time. STEPH: So you just touched on a topic that's really interesting to me or a particular space. You're doing a very kind thing where you want tickets to have lots of context so that people feel confident when they're picking up what's the action item to be done. And for someone that's new, that's incredibly helpful, and I think more important since they are new to that world. But in general, my spicy take of the moment is going to be as developers; that's part of our job. If we notice that context is missing or if we're not clear about the action item, is to think through what is it that I'm missing? Who do I reach out to? Who can I go to for help? How can I scope this work? All of that, to me, is very much part of our role. And the idea that tickets always have to be perfectly curated, which I don't think you're saying, but you're just trying to be extra helpful. But if someone were to have that expectation, I think that expectation is wrong. And I do think it is part of our work that then we help make sure that tickets are well-scoped and well-defined and have those conversations with the people creating the tickets or creating them ourselves. CHRIS: I love the clarification there, and I'm definitely in agreement with you. I don't know how picante of a take it is. I would be intrigued. Listeners, let us know. Are we breaking your mold of what things should be? But I do like the idea that it is a conversation so back and forth. And so the idea that as developers, there should just be this very clear list of things to do and you just kind of pick up a card and heads down, just get it done, I don't think that should be the mold. But I do think; ideally, the why is the most important thing that I think should be in a card. So ideally, a card should have little in terms of technical implementation notes and should have more in terms of here's the goal that we're going for, here's the problem, or here's the thing that we're trying to solve. And then maybe a suggestion of like, I think it could be an X, Y, and Z, but I'm not sure. Or we want to be able to send transactional emails, but I don't know any more than that. Our goal is to engage users. Like that last sentence, that last little bit of our goal is to engage users is a critical, critical data point, versus our goal is to solve for a regulatory and compliance issue. It's like, well, those are different. And they will lead to different solutions and different implementations and all that. So yeah, I definitely share the idea that cards don't need to be perfectly specified. And if anything, I think I'm closer to that than it probably sounded like I was. But for that reason, it's totally possible in my mind, that work will be done in a way that after the fact, I'm like, "Oh, sorry, there was a misunderstanding here. Let's revisit this work." And so, my goal is to try and stay connected and have a feedback mechanism at the end of the process. So when the work is done, be able to spot-check it rather than trying to have to watch it as it's happening or proactively define everything in excruciating detail such that exactly the right things happen all the time. So I'm moving to a place of ask forgiveness, not permission. That's the wrong analogy here. But that idea of like, we can clean it up after the fact, that's fine. And we don't need to try and prevent any sort of things, or at least that's what I'm exploring. STEPH: Yeah, I love that you highlighted having the why. I adore that when that's on a card just because I then I want to know the goal because then that's going to help me ask questions and think about scoping versus if it's like a very specific implementation, then I feel so narrowly scoped that I don't feel as confident that I can be like, okay, I know why I'm doing this versus I just feel very directed to do a thing, and that's incredibly helpful. I have also felt the pain that you're mentioning where it does feel like a ticket has all of the work clearly defined, and the goals, and the whys, and it can have everything there, but just something gets lost in the communication. And so someone implements something in a way that is how they interpreted the work versus it's not actually what the ticket or what the goal of the work was to be done. So I appreciate that where you are looking for ways to tweak things to make sure that whoever is picking up that ticket will have the same interpretation that the author intended for them to have. And then if that does happen, and things get misaligned, then you chat and figure out ways to improve it. I think that's the point that I was really thinking about, and my air quotes, "hot take," is that as developers, a big part of our job is communication, and then also sharing the knowledge that we have with other people. And so if someone is expecting that they can just always pick up work and never talk to someone, I don't know, maybe you're in the wrong business. [laughs] That's my hot take. CHRIS: I, for one, like the hot take. It is nice and ever so slightly spicy. STEPH: Thanks. Yeah, I just think communication is incredibly important. Earlier, you mentioned, I don't think we were on mic at the moment, but you mentioned something about a new Git alias. And I am very intrigued on hearing about what you've added, what it does, all the details. CHRIS: All the details, that's probably too many, but some of the details I can certainly provide. So I have two new Git aliases; one is Git gone, which is probably the heart of the whole thing. And so the background of this is I found myself pushing the green merge button on GitHub more. We've introduced some branch protection stuff, which I've talked about in previous episodes. And I dream of the day that one of my good, good friends at GitHub will give me access to the merge queue beta. Please, please, I implore thee. But in the interim, still clicking the green merge button more often than not. STEPH: Wait. I have to ask to help you in this dream. Are you forwarding these episodes to someone? You can just take a clip of you saying, "Please, please, please give me access," [chuckles] and just forwarding that or mentioning someone at GitHub or GitHub in general. CHRIS: Just leaving voicemails for people with a Bike Shed section of me begging for access to the merge queue beta? STEPH: Yeah. [laughs] CHRIS: No, I'm not. But maybe I need to up my game. You're right. [laughs] Someday, I'll get there. And that will only exacerbate this issue that I'm feeling, which is again, I'm clicking the merge button. That's what's happening. And as a result, that means my local branch is now like it's done its job. You've served me well. And in the Marie Kondo sense, I need to hold you up, thank you for your service, and then let you go. But I obviously wanted to automate that. So Git gone does that automation, and it was fun. So I found a blog post which we'll include in the show notes, that had most of the pieces here, but it was still fun to play with the shell pipeline in a way that I hadn't in a while. So it does a Git fetch and then git-for-each-ref with a particular structured format that references the upstream of the branch then uses awk to search for the word gone. Because Git, if you print it out in this particular way using this format, it will say the local branch name and then the upstream. But if you've deleted the upstream, it will specifically say (gone) in brackets, so you can actually use that to filter them down. And then I pipe that to git branch-D so..well, xargs of course. I love a little shell pipeline. As an aside, these are fun little things to build up. So that is Git gone. And then the other one that I have is Git down, which is what I use more. And Git down works on top of Git gone, so it's Git checkout main and and Git pull and and Git gone. But that means I get to type Git down into my terminal whenever a branch happens to get merged in the upstream land. [laughs] STEPH: [laughs] Oh, that's adorable. I love it. I like the Git gone, and yeah, I like the Git down just for fun. You are inspiring me where I now really want a Git bless your heart that's like maybe a Git blame or a Git revert. [laughs] CHRIS: I've definitely seen people do Git praise as an alias for Git blame. STEPH: That's nice. CHRIS: But Git bless your heart is...ooh, I love that. STEPH: [laughs] I might have to add that just so I can type it, and then someone can say, "What are you doing?" [laughs] Cool, I love it. CHRIS: Little things, little fun bits to add to your day and to automate and have a little fun while you're at it. So that's where I'm at. STEPH: All about the communication and fun. That's what I'm here for and the singing. Let's not forget the singing. CHRIS: And the singing, of course. STEPH: [singing] On that note, shall we wrap up? CHRIS: Let's shall. Oh. STEPH: [laughs] CHRIS: The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Bye. ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

Giant Robots Smashing Into Other Giant Robots
414: Sagewell Financial with Sam Zimmerman

Giant Robots Smashing Into Other Giant Robots

Play Episode Listen Later Mar 10, 2022 39:22


Sam Zimmerman is CEO and Co-founder of Sagewell Financial. Sagewell is building a banking platform for the needs of folks who are trying to retire and live off their savings and income as intelligently and as well as possible. Chad talks with Sam about deciding what their first product should be and what they would be bringing to market, finding the right partners, and minimizing risk to make a business and a product that works. Sagewell Financial (https://www.sagewellfinancial.com/) Follow Sam on Twitter (https://twitter.com/Ferrum_of_omega) or LinkedIn (https://www.linkedin.com/in/sam-zimmerman-35152a22/). Follow thoughtbot on Twitter (https://twitter.com/thoughtbot) or LinkedIn (https://www.linkedin.com/company/150727/). Become a Sponsor (https://thoughtbot.com/sponsorship) of Giant Robots! Transcript: CHAD: This is the Giant Robots Smashing Into Other Giant Robots Podcast, where we explore the design, development, and business of great products. I'm your host, Chad Pytel. And with me today is Sam Zimmerman, CEO and Co-founder of Sagewell Financial. Sam, thanks for joining me. SAM: Thanks so much for having me, Chad. CHAD: I've been following along with Sagewell Financial for a little while now, given our cross-histories and the fact that we worked with a few companies that you've worked at in the past. So I'm aware of what Sagewell Financial is, but I'm not sure that all of our audience is. So I think a good place to start would be by giving folks a little bit of an intro into what Sagewell Financial is, and then we'll touch on the founding story and go from there. SAM: Awesome. So, in a sentence, Sagewell is building the digital banking that our parents deserve. To expand on that even more, America's retirees are a really interesting and important and powerful demo in American culture at large. There are 56 million Americans on a fixed income. And last year in venture capital, nearly $100 billion went to fund financial technology companies rewriting all of finance. And of that 100 billion or a little under, less than a fraction of a percent went to America's seniors. And so we are trying to build banking from the ground up for the needs of folks who are living on a fixed income who are in their golden years and aren't thinking about that new job or making new money. We're building a bank for folks who are trying to retire and live off their savings and their income as intelligently and as well as possible. And that looks really different than the bank that a millennial or a Gen Z user might have. CHAD: So that's really interesting. Right or wrong, what are the reasons that this historically hasn't been a target demographic for investment? SAM: So the prevailing assumption among venture capitalists was (We're changing that and hopefully changing that quite quickly.) was that retirees aren't open to changing. Beyond that, they're also not technically sophisticated. These folks don't know how to use a phone or aren't open to a bank that might not have any physical branch. They are set in their ways. They're not going to move branch, or they're barely going to watch a new TV show. A lot of folks who are trying to talk...imagining a grandma or a grandpa was really what the venture capitalists are drawing on often when they're thinking about why a senior wouldn't expect to have a bank with all the new features that the millennial might. CHAD: Well, that one is certainly changing, especially as the venture capitalists get older themselves. They probably realize that that's an outdated notion in terms of the technical aptitude or familiarity of that audience, right? SAM: Exactly. And it's a fascinating moment. There are 10,000 boomers who turn 65 each day in America, about 4 million folks each year. And those folks were about 40 whenever the.com boom passed. They've been using email. They have XE and PayPal. And importantly, why we're building this company now is that COVID changed seniors' digital lives more than anyone else. ARP reports how 70% of all American retirees know how to use Zoom and video conferencing software nowadays. Across the stack of digital goods and services, seniors were actually the group that was most moved online. And so, from where we sit as entrepreneurs, we saw a massive market, an exogenous effect creating a disproportionate opportunity. And so we began designing and iterating on and understanding our user to build a product that met those needs with this massive and growing market. CHAD: Banking is a highly regulated complex space. And I imagine from day one you're looking at that and saying, "Well, we might want to do everything eventually, but doing everything is going to be difficult." So what was the process you and your co-founder and the team around you used to decide what the first product should be and what you were going to bring to market? SAM: Our founding team spent almost nine months in user interviews and user research across what one director of finance at Capital One called geriatric finance. We talked to hundreds of folks, and a lot of our assumptions about what the simplest or most low-trust or quickest to use service might be were actually totally turned on their head in a really interesting way. Another reason why venture capitalists aren't so confident you can reach this demo is a couple of companies have come before us, and a lot of them followed, in financial technology, a Mint-like model where you log in, and you share your various bank credentials. They pull your credit card transactions and bank transactions. And one of the really surprising things in our hours of user interviews was that that model was really unpalatable to this demo. They actually thought it was a lot higher trust to share bank credentials than it was to actually open an account. And so we began thinking, what's the highest engagement, most common accessible feature that our demo is familiar with? And that's already broadly online. And let's start there. And the original insight came with a woman she was from Pennsylvania, and we were talking. We built this kind of mint.com-type prototype to try to help imagine banking for her needs without this high trust checking account. And she was like, "Oh." She was aghast that we were even considering asking for her bank credentials. We heard that, and then we said, "All right, no worries, no need to do this product demo." And then she was like, "But I really love Chime, and I really love Chime's checking account." And we were like, "Wait, you have a digital bank account?" And she's like, "Yeah, I love Chime." And it was this moment where thinking about our user, what trust meant to them, what was familiar to them, and what being online meant to them opened the floodgates and helped us really understand this user and what that first product needed to be. And so our initial product is a checking account. It's got a variety of senior-specific features around and enabling it. And it's built incredibly excessively to be available to folks who use technology in all sorts of ways. But we started with the basics because that's what our members are most familiar to and most expect. CHAD: So you say in the fine print on the website that Sagewell is a financial technology company and not a bank, and your banking services are provided by a partner. What was involved in actually bringing that online, finding the right partner, implementing the features? What did that look like? SAM: Yeah, it is an incredible time to be building any sort of banking in America around the world. So to that point earlier, $100 billion was pumped into financial technology companies. And so as a result, there are so many companies and so much innovation happening in banking and fintech broadly. And so starting and figuring out what vendor to work with was actually what our strategy from a banking and regulatory perspective was. And in turn, what vendors and in-house technology we needed to build was one of the hardest initial challenges that I've ever had to face in building a company. It is still, despite what many...you'll see a lot of ads, you know, "Have a card online in minutes." It is still in today's day and age quite an achievement to build banking and get it online, and servicing your customers in a scalable and sustainable way. And so we spent a lot of time early on in the architecture and vendor selection process and product strategy process thinking about what vendors to go with; what we were going to build in-house. And before ultimately breaking ground about three months after we began, we set the product itself, which was going to be a checking account for retirees. CHAD: What were the factors that went into choosing the partner that you ultimately chose? SAM: Beyond your standard enterprise vendor selection, we wanted to make sure that it was secure, and we wanted a specific set of features. In our space, there are about six different companies that provide what's called Banking as a Service technology. And so that was one of our key vendors is the technology company that works with the bank to allow us to open checking accounts, fund accounts. And most of those companies have been around for only a few years. And so their products themselves are hardening and being built. And about $200 million I would say has been invested in those companies last year. And so we wanted one that was well-capitalized. We wanted one that had not had any IT security issues. We wanted the underlying bank to be aligned in our mission. Retirees have a variety of specific financial needs. A lot of our product development involves working very closely with the bank. And so, we needed to make sure that the bank itself that they worked with was on board. And lastly, we talked to other customers, and that was ultimately the most valuable thing in our experience and not just the customers that they refer you to but the customers who have left for one reason or another. Those were the major factors that we chose in our Banking as a Service provider. And then, beyond that, that's one piece of the puzzle. In our bank tech stack, we're looking at around 15 different partners across all parts of banking. And that's the largest and most important one. And those were the criteria we used to select. CHAD: I often say when I'm looking at building a product or service, and we look at those integration points with external vendors, it is one of the riskiest parts of building a product because you're not in control of it. So from a business perspective, it's risky. But also, from a technology perspective, that's where estimates can get out of whack. And things can work not like you're expecting or like the documentation said or just surprises crop up along the way. Or when something goes down, your product is broken. And your entire product [laughs] basically is built on those vendor relationships. So, how do you minimize that risk and work in that environment to make a business that works and a product that works? SAM: [chuckles] I suppose the answer is with a lot of prudence, thoughtfulness, and care at a high level. CHAD: [laughs] SAM: I was actually just talking with a CTO friend of mine just talking about how in a lot of startups, one of the skills that I most ask of engineers and engineering leaders early on is vendor selection and how I hadn't seen an interview process that really helped get at that. It's a core part of a lot of technologists' jobs and particularly a lot of engineering folks' jobs. The API docs looked good but did he test it or evaluate it? Was there a third-party tool you could have used instead of building in-house? Those are the sort of questions that a lot of times early-stage startups are answering all the time. And I had yet to see an interview that got at that. So it's a really shrewd point and one that I hope that as technologists and particularly early-stage startups become more about really going deep in one area and then leveraging third parties elsewhere, I hope that we start actually hiring and developing criteria to do that with the people that we assemble. I think the first part what I would say is we described a little bit about the risks. We went through a risk mitigation exercise, which smells very enterprise-y. It's kind of the sort of thing that you would expect exists in some massive waterfall with a Jira board mainframe computer but just listing like, here's this integration. If this were to happen, what would we do? If the API went down, what control do we have, or how could we minimize the impact on our customers? That exercise across some of our biggest integrations helped us select and take on the risks we wanted and avoid the ones we couldn't. So there was a lot of conversation about the sorts of failures we could put up with and how we could put up with them, and the sorts of failures we couldn't. And then really testing for the ones we couldn't to make sure that we were making as good a choice as possible. Despite that thoughtful answer, it was the best we could do. I would say that, particularly in a space that's as fast-moving as Banking as a Service, I would say that a lot of it is still that soft skill, that relational conversations with other teams and folks and whether you trust the team that you're trusting to execute and build what they said they're going to build and that hiring skill but also a good bit of luck as well. CHAD: So correct me if I'm wrong, but up until Sagewell, where you're CEO, you had been CTO of the other companies that you founded and worked at. Is that right? SAM: Yeah, that's correct. CHAD: So, what has the change to being CEO instead of CTO been like for you personally? And was that choice clear from the beginning with Sagewell? SAM: So far, it's been incredibly rewarding. I would say in between startups; I actually volunteered at an organization called PathCheck. And while my title was CTO, the scope of that included partnerships, vendor negotiations, CISO exercises, product. It was a pretty expansive CTO role. And I found myself really energized by the breadth and the ability to work with even more really talented, thoughtful experts in their own domain and empower them to do more. And so I knew in my next role, I wanted more of that breadth. There's an essay that classifies folks as foxes who can do a little bit of everything or hedgehogs who can do one thing really well. And I'm a super fox. [laughter] I love doing lots of things. And so CEO to me is just like an opportunity to...it's maximizing breadth and maximizing difference of experience. And I transitioned, I'd say, from a normal CTO role to a beefy CTO role to making CEO a pretty natural step from there. CHAD: And your co-founder is named Jeff Wright, and he's the COO. How did you meet him and get started with Sagewell? SAM: Jeff and I, it's been wonderful. I was trying to figure out how I was going to get engaged in pandemic work in April of 2020 after leaving my last startup while it was being sold to Capital One. And I was talking with a founder friend of mine, a guy named Ty Harris, who is the CEO of an Insurtech company called Openly. And he was previously the CTO at Liberty Mutual. And Ty and I had a couple of lunches and conversations, and I was talking to him about how it is getting involved in COVID stuff and how I was ultimately my species as an entrepreneur, and I was going to be building something again. And he connected me with Jeff, and Jeff and I touched base quickly in April. And it was a little bit like a frog in the pot sort of situation where it started like, yeah, maybe we could build a company. Let's riff on some ideas and see what's out there. And it was a really, really natural progression from August to a couple of evenings, maybe a Saturday call or two, to most evenings and definitely a Saturday to oh, man, when should we transition? CHAD: You were both working full time on other things at the time. You were working with PathCheck. SAM: Yep, exactly. And so he was the CPO at a company called Plymouth Rock, and I was working at PathCheck. And not to go into PathCheck's story too much, but PathCheck was largely deploying a research technology, the Google and Apple Exposure Notification protocol. And it became clear that most of the states that were going to do anything were already going to do it. And so, it was natural to start thinking about what was next in August and September. And so, as my species does, that then became the night and weekend project to figure out what's next. CHAD: So you mentioned that this is a space that is typically not strongly funded. So was that a challenge for you as you were getting started? How did you get that initial, you know, where did your initial funding come from? And I know you recently raised, at least it was announced, 5.3 million in January. So what was the transition from those early days? Where did the funding come from to ultimately getting the investment in this last round? SAM: Jeff and I worked in the fall of 2020, met our CTO, Chris Toomey, in November actually from connection through a friend. Early on, we were a team with a demo. We really knew that we cared about seniors, and our background is in financial services. We were trying to think of a new product for seniors and so a financial product for seniors. And so, around January, we sharpened our pencils on the user research side of things and the product side of things. And once we had a clearer sense of the product direction we wanted to take, ultimately building banking for retirees, we began the fundraising process. CHAD: So were you essentially self-funding at that point? SAM: Yep. So we were self-funding from January-ish till May. I find that skin in the game to be… I wish I was the sort of founder who could think about flawless ideas without a little pressure. But in my experience, it's actually been where unless I jump in, unless I can have a little bit of pressure, my ideas aren't often as refined as I'd like. And so Jeff joined it full-time in February. And then we fundraised through April, closing a 1 million pre-seed, which is pretty common in fintech. Most financial technology companies the banks won't talk to you until you have at least a million dollars in funding. And so we raised the money we needed from...and who did the money come from? It came from Point Judith Capital, who actually had invested in Ty, the guy who connected us, with his company Openly. So we had our initial conversation with David, who's been absolutely wonderful at Point Judith Capital. And also, Jeff and I knew that innovating for a vulnerable population, ultimately retirees, meant that we wanted to have folks from the beginning who represented the seniority and seriousness with which we are taking our work. And so the second investor who in between the two of them took most of that million was Crossbeam and Raj Date at Crossbeam, who's the former Deputy Director of the U.S. Consumer Protection Bureau. We really wanted folks around the table who knew what innovation looked like and fintech innovation like David, as well as folks who understood the world of government and finance like someone like Raj to innovate thoughtfully with this demo. CHAD: Was it difficult to get those funding rounds? SAM: The first one? Yeah, the first one was about two months. I thought it would have taken about a month. The second one the market is pretty crazy right now. And I would say between my first company and my second, it used to be that you'd set aside six months to fundraise, and so I'd prepared for a six-month fundraise. Started kind of in early October two weeks in, and they were like, "Wow, you've already been in the market for two weeks?" [laughter] And I was like, what? I was totally off base in terms of what was the new normal. Ultimately, that round came together in about a month and a half as well. And so we had a lot of interest. The second round that 5.3 million went from not a ton of interest to tons of interest and lots of folks around the table and having to push folks out or turn folks down pretty quickly. The first round, I would say for a pre-seed, one to two months given that the idea was hardening, sounds about right. The second one was about one to two months but was a little...a lot of people would get excited by the market; they'd get excited by the team. And then they'd say, "You can't get a senior to open up a bank account," and then they'd come back. And then we found one believer alongside David and Raj, who had been with us. And once we got the folks at 25Madison and Merrill, especially, the rest of the round came together really quickly. Mid-roll Ad I wanted to tell you all about something I've been working on quietly for the past year or so, and that's AgencyU. AgencyU is a membership-based program where I work one-on-one with a small group of agency founders and leaders toward their business goals. We do one-on-one coaching sessions and also monthly group meetings. We start with goal setting, advice, and problem-solving based on my experiences over the last 18 years of running thoughtbot. As we progress as a group, we all get to know each other more. And many of the AgencyU members are now working on client projects together and even referring work to each other. Whether you're struggling to grow an agency, taking it to the next level and having growing pains, or a solo founder who just needs someone to talk to, in my 18 years of leading and growing thoughtbot, I've seen and learned from a lot of different situations, and I'd be happy to work with you. Learn more and sign up today at thoughtbot.com/agencyu. That's A-G-E-N-C-Y, the letter U. CHAD: Given that you were able to put together a round quickly, how do you decide ultimately not to take even more money? What are the factors that go into deciding how much you're trying to fundraise and how big the round is going to be? And is there pressure as you're doing that to maybe go even bigger? SAM: Yeah, we had, I would say maybe seven and a half million dollars interested. And ever since we've closed, we've had multiple firms who are interested in a new round of capital. The market is really, really quite founder-friendly right now. I think ultimately, for any founder, what you're trying to do is create as much value with as little capital as possible. That's ultimately the game that you're trying to play now. For a little baby company, it's often really hard to figure out how much money or how much value you'll be able to create over what amount of time. There's so much to figure out. There are so many bets and learnings and risks that it's often very hard for a company to say, with $5 million, I'll create $20 million in value. So ultimately, if you're a founder, you're incented to give away as little of the company as possible and create as much value from that. And so when we were doing our modeling, we actually thought that it was somewhere closer to four of what we needed to create the amount of value needed to raise our A. And we ultimately bumped it up to 5.3. And there's a good bit of advice you hear a lot among founders that raising a bit more than you think is prudent, and anyone who has managed a budget knows how that can go. So we ultimately did go up to 5.3. But taking more would have meant that we were paying a premium where we could get that million dollars maybe in a year's time, and we'd be giving away a quarter-point or a half a point of the company for that million where we might be giving away 1% or 1.5% of the company now. So it's all about creating as much value with as little money as possible. And it's easy to get lost in the big rounds and the big numbers. But ultimately, it's pretty simple math. CHAD: And correct me if I'm wrong, and this is a question as much as a statement. So to reiterate, the rounds you're talking about are seed rounds. And so traditionally, what that means is that the majority of work that you have to do is just making the product. But in the space you're in, there is a point in time where you've made the product, and you've shown the traction, so what you have becomes more valuable. And so it might be that the next round, which is maybe a Series A, a significant portion of that capital would be spent on something else like marketing or sales teams and that kind of thing. And you're growing beyond just the product development at that point. Is that how you're thinking about this, or am I wrong? SAM: So it's funny that it's really changed the names. The round size what they mean has changed more in the last two years than ever before, and I would say that, particularly in fintech, because fintech has a number of unique challenges. So I would say that that $1 million round that we raised in May that was really about building a very basic product, a very truly minimally viable acceptable product. And then the seed round in fintechs is often about getting to product-market fit or just demonstrating you can reach your end consumer or target user. In fintech, it's often not quite as much tied to a certain amount of revenue at that stage. It's often about just demonstrating that you can get to that user, and that's because, in financial technology, the cost to acquire is often quite high. And so for a company that only has raised, say, a $5 million pre-seed because of the gravity, because it often costs hundreds sometimes thousands of dollars depending upon the market to acquire a specific user, the math is such that you're just not going to have that many users, and you're not going to be able to get to a certain amount revenue. And so often in fintechs, 1 million gets you...that pre-seed gets you that initial product. The seed is about demonstrating that you can scalably get to that end user. And then the series A is really about blowing that out and starting to exploit that marketing and acquisition machine that you've been building to start creating revenue. That's a little bit industry-specific. Other industries will have similar or different terms. And depending upon what sort of branding a firm might want for the round, you also might hear $100 million pre-seed. You hear those things as well. It's a crazy time to be building a company. CHAD: So you mentioned Chris Toomey, who's the CTO of Sagewell, and he was previously at thoughtbot. As a prior CTO, what were some of the things you looked at in terms of finding Chris and deciding he was the right one to join your team as CTO? I imagine your standards were pretty high. SAM: Yeah, and Chris met them quite happily. As a CTO transitioning to CEO, I think you have to understand your strengths and weaknesses as a CTO as well as the learning curve that you might have stepping into your new role as a CEO. And I would say that one of the fortunate things is that Jeff, my co-founder and COO, we actually have a pretty unique set of skills that can span a lot of different domains. And so I would say that looking at Jeff, Chris, and myself, we really had to make sure we had our bases covered to build the financial and technology product we needed. I would encourage folks building a company early on to really think about your strengths and weaknesses, your founding team's strengths and weaknesses. And as I was getting to know Chris, kind of the initial handshake agreement starting to build and prototype various solutions, I think that I was particularly impressed and looking for someone who was willing to have a deeply experimental and MVP mindset while managing the risks of working with a vulnerable population. And so over the course of December through March or April, in dealing with and spinning up a couple of different prototypes with radically different product strategies and end products, I was able to see how Chris was able to be mature and shrewd about where he could cut corners, where he couldn't cut corners and then execute accordingly. It's funny, Chris and I were talking at our one on one a week or two ago. As a CTO, I know a little more of what's possible. I know if I come in and say, "I want the Taj Mahal," I know you'll get walked back down. Chris and I over the past year...I often come to Chris, having already teared down my Taj Mahal. And I'm like, "Well, Chris, what I really need is one little specific problem." And Chris and I actually set a goal between us that I actually kind of come to him asking for the Taj Mahal next time [laughter] or not next time but sometime in the next year. Because I think one of the things I've had to check or do in CEO is let Chris do CTO's job and not internalize all the time his voice and concerns but actually put forth a vision and not be afraid about the fact that it isn't something that we can get to market in a week or that we can't ship in three or four weeks' time, which is an interesting contract that I think we've developed and an interesting growth area. And it's my job to throw out bigger ideas, not to be the one who tears them down all the time, which is fun, and I enjoy doing that with Chris. CHAD: Yeah, that's an interesting perspective. And I often even working with clients and consulting want that because if you're only getting the small pieces all the time, you cannot be privy to the big picture of what we're aiming for. And that will often lead you to maybe not taking everything into account, either that's on the roadmap or down the road. Or realizing, oh, you're disappointed now, but that's because I didn't know that you wanted to do this. If I had known, then we could have done this in a different way or something like that. And so, getting a sense of that big picture is often important. SAM: Yeah. And it's a fun, I'd say...yeah, and growing with Chris and figuring out that he's the right person for the role as a CTO turned CEO means kicking off the ladder and actually just stepping into my role and letting him do his, which has been a fun contract to establish. CHAD: So, did you work with Chris as a contractor before committing to him as CTO? SAM: Yeah, we were in a consulting relationship. I think Chris was politely under billing. And the pretext is always that this was something that we were really aiming to build a company together, assuming everything worked out across Chris, Jeff, and I. And so, he did start in that capacity. And then I'm trying to remember the exact timelines. Sometimes the paperwork is well after the actual agreement whenever you're creating these companies. But in a few months' time, definitely by July and probably by May, we were building the company and off to the races. CHAD: Now, is that a path that you would recommend to other founding teams looking for a CTO is to not commit early to really make sure that you work well with someone, maybe through a contracting relationship first? SAM: Yeah, I think ultimately, if you're going to be going on a journey, a decade long journey, a lifetime-long journey, through highs and lows, I think the best way for everyone to know what they're getting themselves into, the excitement, and the reward, and the aches, and the pains and the sleepy [inaudible 33:31] in the morning is by working together, and I don't think there's a shortcut. In this case, it depends a lot on the situation. It depends if folks are in a position where they cannot take pay. It depends on whether nights and weekends are free or they have flexibility in their other roles. But generally speaking, I think that ultimately, you're trusting, and your founding team is going to be taking so many risks together that you want to go in as eyes wide open as possible and have removed as much founding team risk, disagreements, misaligned working styles, misaligned visions, or preferences as possible. My coach used to say that that's the number one reason why companies at the seed stage fail is management teams and founding teams. And so as you're thinking about building your company, and I can't emphasize this enough, mitigating and removing founding team risk, however possible, with consulting being one of them and navigating a tough conversation or two being another, is absolutely core to removing as much risk as possible for your startup. CHAD: That's great advice. And just like you and Jeff had a time of working together before you actually started a company together, I think it's great advice to try to find ways to do that with other early members of the team too because it's a big commitment, and you want to make sure that you get it right. SAM: Exactly. CHAD: Well, you've reached sort of the pinnacle of having now someone on your team that used to work at thoughtbot. I think I'd be remiss if I didn't point out that we have another podcast at thoughtbot; it's called The Bike Shed. And Chris started as a host on that show while he was on thoughtbot, and he continues that to this day along with Steph Viccari, who's a team lead at thoughtbot. And so if people are interested in hearing about Chris' work now at Sagewell and following along with the team and the work that he's doing there as well as the work we do at thoughtbot, people can check that out at bikeshed.fm. Sagewell is not a client of thoughtbot. But you've worked with thoughtbot before as a client twice, right? SAM: Yeah, exactly, both at my first company Freebird, which was sold to Capital One, and at PathCheck, the non-profit I worked at. CHAD: So you specifically, I assume, then made an effort to recruit from thoughtbot when you started Sagewell. [laughs] SAM: I would say I know and love the way that thoughtbot approaches building software. And I know and love the people that I've worked with from thoughtbot. And I would say that it was as much a feature of being in the same communities as it was specifying a specific group. But you guys have created a great culture. [laughs] CHAD: I'm just kidding. I didn't actually think that that was the case, but I can guess a lot of the benefits of working with someone who's worked at thoughtbot before because of the level of experience and the level of skill and communication and everything that people at thoughtbot have. But I'm curious, what if I turn that around? Is there a downside to hiring someone who worked at thoughtbot previously to your team? SAM: So one of the things that I love about, particularly early on, we have a hire that we just made recently. She worked at a senior living facility for four or five years and then worked at Wells Fargo for four or five years. And before, we had a bunch of fears, and this new employee listed five or six totally different fears than we ever would have thought of. And so now we have way more fears. And part of that can be unnerving, and part of that can be challenging. And I would say that one of the challenges of working with a team that builds software in such a clear culture is that you might not get all the fears. You might not get certain sorts of diverse perspectives or headaches because of a particular way that product and engineering are conceived. And so one risk...it's kind of the unknown-unknown sort of situation, but it's real in startups which is I think that making sure you have diverse perspectives across the domains where you need to be deeply an expert for folks who are very similar to you is a major risk. CHAD: That's great. Well, Sam, thanks for stopping by and sharing with us. I really wish you and Sagewell and the entire team all the best. SAM: Awesome. It was wonderful talking. CHAD: And if folks want to find out more about Sagewell Financial or follow along with you or get in touch with you, where are all the best places for them to do that? SAM: sagewellfinancial.com is our email. And if you or your parents are interested in what we're building as a customer or a member, you can sign up there. If you'd like to reach me, I'm mostly on Twitter following cute animals and occasionally a good tech post @Ferrumofomega. And if you'd like to contact our company, you can just go to /press and fill out the form there. CHAD: Awesome. And you can subscribe to the show and find notes for this episode along with a transcript of this episode and all past episodes of this season at giantrobots.fm. If you have questions or comments, email us at hosts@giantrobots.fm. And you can find me on Twitter @cpytel. This podcast is brought to you by thoughtbot and produced and edited by Mandy Moore. Thanks for listening and see you next time. ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

The Bike Shed
329: Fire Mode

The Bike Shed

Play Episode Listen Later Mar 8, 2022 31:41


Steph is excited to be headed on a retreat with her mom in the mountains, but before that, she details how she helped troubleshoot a production issue with her team and appreciated their process. She's also looking into tooling around spinning up more machines to process more RSpec tests. Chris had a developer start their new job at Sagewell and highlights how they involved the new person in rectifying potentially missing and/or confusing existing documentation. He also has a gripe, and that is accounts. Handling too many accounts. Additionally, he talks about triaging an error and how it was tough initially to understand if something was actually broken. And then it was even harder to understand what was broken. So he paired through it and used the power of putting two heads together. This episode is brought to you by ScoutAPM (https://scoutapm.com/bikeshed). Give Scout a try for free today and Scout will donate $5 to the open source project of your choice when you deploy. Become a Sponsor (https://thoughtbot.com/sponsorship) of The Bike Shed! Transcript: CHRIS: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Chris Toomey. STEPH: And I'm Steph Viccari. CHRIS: And together, we're here to share a bit of what we've learned along the way. So, Steph, what's new in your world? STEPH: Hey, Chris, I am going on vacation next week, and I am so excited about that. It's going to be pretty much a week long. It's like a Tuesday through Friday ordeal. And it's a trip that I'm taking with my mom. So over the past year, she's gotten super serious about her health and nutrition and done a phenomenal job of being very focused on a plant-based diet, which is basically healthy vegan food is what that comes down to. So there is a retreat that's taking place in the North Carolina Mountains that she's really excited about. I'm going to go with her. We're going to do lots of cooking, and hiking, and hanging out in the mountains, and it's going to be lovely. CHRIS: Well, that does sound lovely. STEPH: Yeah, it seems like a really perfect time to disconnect just because you're headed into the mountains. So all you should take with you are books and things that are not iPhones, and tablets, and computers, and screens. So I'm looking forward to that, just to be away from screens for the week. On some more technical news, this past week, I helped troubleshoot a production issue, which was a bit novel for me because the work that Joël and I are doing with our current project it's all in the testing realm. And so it was probably around 10:00 o'clock at night my time, and I got a ping on Slack. And it looked like I was getting called in for a production issue. And I was like, I have touched zero production code. [laughs] So I'm very intrigued how I could have broken production at this point. And so I looked into it, and it turned out that it wasn't necessarily related to a commit that I had authored, but it was for a commit that I had reviewed and then approved. And so their strategy is they create a new channel. They'd gotten a ticket that an error was occurring. And then the site reliability team created a new Slack channel, and then they pinged everybody who either authored, reviewed, and approved that change to be like, hey, we think the issue is related to this commit. Our plan is we'd like to roll it back. But before we do, we just want to check in with folks who have more knowledge to help us confirm that, yes, this error message seems related. And I really liked that approach. I really like the idea that it's not just the person who merged the commit that then gets pinged on it, but it's like everybody else who happened to look at this and review it come help us too. So we spent some time looking into it, confirmed that yes, indeed, it was related to that particular commit. And then their team did the wonderful thing of then rolling it back. So then, it was no longer an escalated issue. And so then I asked, "What else can I do to help?" And they said, "Well, from here, it's no longer a production issue. So tomorrow, just follow up with the author and let them know and issue a fix for the bug, and then merge it like normal." So we're back in that normal pull-request flow, very calm. And overall, I just appreciated their process. I like very much how they pulled more people in because I think some of the other people that were involved weren't online, which makes sense because it was really late. So that way, you just spread in case some other people really aren't available that then hopefully you'll get lucky and one of those three or four people are available to help you troubleshoot. CHRIS: That does sound like a really nice and thoughtful and intentional bug response, communication, procedure, rollback, et cetera. All of that sounds like it worked very well and is nice to have. And it's the sort of thing that a larger organization ideally gets to, having these sorts of processes. Spoiler alert, later in the episode, I will talk about the other side of it of being a very young organization and trying to be like, wait, is this a bug? Is this not a bug? Should we roll back? What do we do? That's actually my topic de jour. But what you're describing sounds like the calm even in the case that there is a fire sort of like, yep, we've got procedures. We have workflows. We have communication channels and ways that even the exceptional things can be handled in an ideally as calm as possible way. So that's awesome that that's what you got to experience there. STEPH: Yeah, getting called in at 10:00 o'clock is never fun for anybody. But when it happens, because it's going to happen, then I appreciate the thoughtfulness and that process that they put behind it. So it all went fairly smoothly. And it was also one of those fun things where I haven't met...like this is a very big organization, so I hadn't met any of those people. So when I got pinged on it, and then I hopped in, I was like, hi, I don't know anything about this process and what y'all are doing, but I am here. I'm here to help. Where can I look? What can I do? So it was also a fun endeavor in that regard to just be like, I don't know what I'm doing, but I am here to help. Please let me know how I can help. And it ended up working pretty well. So yeah, that's been a fun adventure for this week. How about you? What's new in your world? CHRIS: What is new in my world? Well, we had a developer start this week, which has been really wonderful. Unfortunately, we had scheduled their first day to be Monday, which was Presidents' Day, and that's a holiday. So we got out in front of that one and figured it out. We're like, no, no, actually, feel free to start on Tuesday. We'll not be around on Monday, so you shouldn't be around on Monday. But then, on Tuesday, they started. And we intentionally structured things such that we have a contractor that has been working with us for like seven or eight months now. So it's been a long time and been very formative as well the work with that contractor. So this is their last week, and thus, we very purposefully brought the new person on the team and that contractor together to maximize the amount of pairing and overlap that we have there just to try and as intentionally as possible grab whatever is in their head, get another point of view. Because this new individual on the team will be able to work with myself and the other full-time developer on the team a bunch moving forward, so we want to maximize their overlap with the person who is on their way out. But otherwise, it's been great. We're a young organization, so the version of onboarding it's me running around setting up a lot of accounts, forgetting to set up other ones, getting pings in Slack, and then following up and setting up another account. Eventually, I hope that there are checklists and formalizations and, ideally, one-click SSO magic that makes all of that work. But for now, I'm happy to chase it down. But really, we're just leveraging pairing as much as possible as the onboarding tool to make sure that where we don't have formalization, procedures, documentation, et cetera, as thoroughly built out as I would love to be at, we can shore that up with some time with other humans. STEPH: That's awesome. It's always fun having someone new to join to highlight all the things you need to automate or at least have a checklist for to then help them onboard. But that's really exciting that you've got a new teammate. CHRIS: Yeah, definitely very exciting. And they've been great. They've hit the ground running and a couple of pull requests already and just contributing very effectively within their first couple of days. So that's always wonderful to see. We are definitely taking this moment to document what is undocumented or update the README where it needs to be and start to make that checklist. We have another person who will be starting in about two weeks' time. And so, ideally, that will be even a little bit more fleshed out of a process. So slowly, incrementally get a little bit better with each we add that we get there. STEPH: How much do you involve the new person in creating that documentation? Is that something that you ask them to help build, or is it something you take ownership of? What's that balance? CHRIS: It's interesting. So definitely some I want to be with that person because I think it can often be the easy first PR is an update to the README for like, oh, I tried to set up the app, and it did not work. For this reason, I have now updated the README, and now there's a pull request. And we get to experience that flow via the very low-stakes change of updating the README. So that's a definite one that I like to have. The other is I'll typically ask for the individual to capture as much as possible. There's a very delicate line in my mind between empowering them and being like, yes, absolutely. We're young. We don't have everything documented. So feel free to make changes where that makes sense to you. But at the same time, I know that joining a new team can be complicated, can be intimidating in certain ways. You're not sure what's okay to change? What's not okay to change? That sort of thing. So I simultaneously don't want to put the pressure on someone to be like, "Yeah, no, change anything you want. Literally, nothing is stable here. Nothing's glued to the ground. So feel free to pick up anything and throw it out the window." That feels too far in my mind. So I don't have an actual answer like, I'm ideally calibrated at this point. But it's sort of those two tensions that I'm holding in mind as I think about that. STEPH: Well, I really like your answer. I like that balance because I think it's really nice to include the person in those changes and also just because they're going through it. So they happen to have that insight, and it's fresh. But I agree, when you're joining a job, you want some stability and confidence that the people that you are joining that team with are also working hard to make it a very positive onboarding experience. And if you just were to push all of that responsibility on to them to be like, "Yeah, we know. We don't have this organized yet. So you tell us everything that we need to do," that would feel unkind to that new person. I think as a new person that I wouldn't fully enjoy that. I don't mind some of it, but I wouldn't want all of it. I'd have nervousness around ownership, around improving processes, and who that belongs with. CHRIS: Sort of a classic case of it depends, or it's a little from Column A, a little from Column B, but definitely some, just hopefully not too much. STEPH: The Goldilocks of onboarding, some onboarding responsibilities, but not all of them, just the right amount. [laughs] CHRIS: Shifting gears slightly, though, I just want to gripe for a minute. I'm just going to gripe. This is not my normal mode, but I'm going to lean into it. STEPH: Do it. CHRIS: Accounts, just accounts. I have so many accounts now. There are so many across different systems, and I'm trying to do the good thing, which is let's stop using personal accounts for anything and only use organizational accounts for the things that are for work. And some organizations do a great job with this. GitHub, I'm looking at you; really well done, super happy with the way that you folks have implemented accounts. You get that I am one human being that contains multitudes. I am my personal self; I am my work self. I am maybe even another version of work, and you get that. And you usually let me exist as all of those versions of myself and, man, do I appreciate that. Heroku, you're okay. Like, it's all right. You treat the different facets of me as different accounts, but that's okay. You make it relatively easy to switch between. Although you do make me two-factor auth and re-login every single day, and I don't love that. So I don't know what's going on there, but fine. Trello, aka Atlassian, I guess at this point, come on, what are we doing? What's going on here? So originally, I had started, and I had the one Trello account, and I had my personal boards. And then there was the Sagewell organizational account. And within that, there were some boards, and I would just bounce back and forth. But I realized, no, I need to do the right thing. So I created a new Trello account. And now Atlassian just forces me to switch between them, and it loses the link that I'm going to often. It's a different login interstitial screen. And it constantly shows me that like, hey, you don't have access to this. Do you want to switch accounts? And I say yes. And then they take me to a screen where I can pick between two options, the one that I was that didn't have the ability to do it and another. And as a developer, I know that the thing I'm about to say is not fair. But come on, folks, you could know the answer to this question. There are two, and one is the wrong answer, so the other one is probably the right answer. You don't need to autolog me into that; I get it. Just emphasize it because they almost look identical on the list. I have now accidentally tried to request access with my secondary account to my other account, and I can't get out of that state. So now, one of the ways that I try and do this it shows me a list of them to pick. The other it says, "You have requested access. We're waiting to hear back." And I'm like, no. So anyway, that's a thing. STEPH: So I know people can't see me. [laughs] So I'll narrate that I'm dying over here because I very much appreciate that we are positive people. We are very focused on bringing positive energy, but the descent into the amount of shade that you're throwing at different applications [laughter] just really made my day, and I feel that pain. I have felt that pain with Atlassian and can relate. And we should have some gripe sessions. This feels healthy. This feels very...okay, well, I don't know for you. I'm the one that's laughing and getting joy out of this. I don't know if it's helpful for you, but it feels very cathartic to me. [laughs] CHRIS: It is definitely somewhat cathartic. I think there's utility in having these sorts of conversations. And throwing shade at Atlassian, whatever, they're doing fine, so I'm not super worried about it. But generally, we try and keep things positive because I think that's, frankly, a more effective way to communicate. But occasionally, it is useful to look at the things where I'm like; that is a pattern that I do not want to repeat. And I'm sure that there are complex organizational enterprise-y reasons that it has to be this way. But I can look at that and say never that. That experience as a user is like, wow, yeah, I just tripped over nine layers of your enterprise there just trying to do very simple day-to-day things for myself. So I want to avoid that. I've griped about that one login, not the company OneLogin. But that one login page that I've experienced where I start to interact with the form, and suddenly some JWT handshake in the background happens, and I'm now logged in. And it just rips the page out from underneath me. That is unacceptable. That is not okay. And I really do think there's something worth occasionally looking at those and being like, well, not that. But anyway, I should probably stop my gripe session now. STEPH: [laughs] Well, if I may join in, I have one that I'd like to share. Since we're on this -- CHRIS: Throw it on the pile. What else we got? [laughs] STEPH: [laughs] So there was some code. There was a piece of code that I was looking at that was very not friendly. It was difficult to understand. It took a while to parse through what are they actually doing? What records are they creating? Why did they choose this manner? Why are we iterating over these particular numbers? What's the outcome here? And I was pairing with Joël and was going back and forth having a conversation trying to be the detectives of why this code exists, and we finally got there. And we finally understood what it's doing and why. And I just lost it for a minute once we finally got there. [laughs] I just thought the way this code is written, it does not improve readability, and it doesn't improve performance. All it did was make my life harder because it was very difficult to read. So all they did was become really clever with the code that they were writing and essentially drying it up, which I have such a beef with DRY because it has caused me pain. And so they essentially were drying up their code or introducing a way to make it just take up fewer lines that took up less vertical space. But overall, I was very grumpy about it. And Joël was very kind about it and was like, "Well, this is the type of code I could see maybe why they did this." But you're right; it doesn't help with readability and performance. And he was helping balance out my grumpy goose moment. I've been having a lot this week; maybe it's just the week I'm in. I'm in more of a fiery mode this week [laughs] with some of the code that I'm seeing, and that was one of them. That was the please, please, please don't DRY up your code. If it doesn't improve readability or performance, there's just no need. There is no benefit. CHRIS: Well, I definitely know that feeling. And I think I've probably, as a developer, gone through that arc where early on I was just trying to make stuff work, and then I learned how to be clever. And suddenly, being clever became a game that I could play. And then, pretty early on, I realized I would come back to my own code from two weeks ago and be like, what the heck does this do? I have no idea. And that's when I was drawn to Ruby. That was one of the things. I'm like, oh, I can write code that looks so much like the clear words that I have in my head about the thing. I like that. And so much of my career has been spent in the let's make it obvious and revisitable. I actually remember very clearly early on in my time at thoughtbot, I was working on something and was working on it with Joe Ferris, who is the CTO of thoughtbot and a very clever individual, and I mean that in the truly positive sense of the term, one of the most capable engineers I've ever worked with. He was describing an anecdote, but it was basically he'd put up a pull request. And someone replied, "Oh, that's clever." And Joe's reaction was, "Oh, crap." Just taking that as not an insult but as someone saying, oh, that's clever in a positive way, and Joe hearing that in the negative form of I went too far here, or this is not obvious in its initial interpretation. That really stuck in my head from there, just his reaction to it immediately of that being not a good thing. And I was like, that is interesting. And all the more so over time, I've come to believe that clever is probably something to avoid in code. STEPH: Yeah, agreed. I'm at the point that if I do see someone who's done something that I do think is clever in a positive way, I will still abstain from using that word clever because I do want to make sure they don't think that I'm saying in a bad way that this is clever, that it's not readable, and it's not friendly. So I totally avoid that word when I'm complimenting someone's code just to make sure there's no confusion. CHRIS: It's one of those words that got away from us that we lost the definition of, and then we came back, yeah. Mid-roll Ad Hi, friends, and now a quick break to hear from today's sponsor, Scout APM. Scout APM is an application performance monitoring tool that's designed to help developers find and fix performance issues quickly. With an intuitive user interface, Scout will tie bottlenecks to source code, so you can quickly pinpoint and resolve performance abnormalities like N+1 queries, slow database queries, and memory bloat. Scout also recently implemented external service monitoring, adding even more granularity when it comes to HTTP requests and API calls. So give Scout a try today with a free 14-day trial and experience first-hand why developers worldwide call Scout their best friend. And as an added bonus for Bike Shed listeners, Scout will donate $5 to the open-source project of your choice when you deploy. To learn more, visit scoutapm.com/bikeshed. That's scoutapm.com/bikeshed. CHRIS: Let's see. In other news, you had mentioned this earlier, and then I had mentioned my side of it but errors in alerting and all of those sorts of things. They're an interesting question. We had a small situation over the weekend that turned out to be kind of real, kind of not real. But I happened to be away on vacation. I did have my computer with me because, at this point, we're early enough. And I'm like, I'm going to take my computer everywhere and just be ready in case it's necessary. And in this case, I did get a ping. I looked into it and what was unfortunate is it wasn't immediately obvious if something was broken or not. And to a certain degree, that's always going to be kind of true. There's so much noise, so many requests hitting a web application. And how do you tell the good ones from the bad ones? And ideally, I could threshold around certain volumes of traffic, but even that's going to have spikes, and ebbs and flows and things like that. So it was very hard initially to understand is something actually broken? And then all the more so to understand what was broken. Thankfully, it was tractable. It was solvable. And we've done, I think, some good work especially considering how early on we are and how we've instrumented things in Sentry, in particular, our usage of Sentry and also somewhat in the logs. But again, I think I've talked about this before, but I'm feeling this tension around there's data. There's data just kind of like, what happened? And right now, we've got logs. That's one of the places that goes to Sentry if it gets escalated up to that level. And we sort of have a weird Venn diagram between logs and Sentry. And then we also have analytics as another thing and then eventually data science, and what do we want to try and learn? And all of these kinds of want different facets of it's not the same data set. But I wonder, is there a superset of data that then we could filter and slice and cut up, do all those sorts of things? I think this is the dream of Honeycomb and platforms like that, but I'm not even certain if that's true. And so I'm in that awkward middle space is how I would describe it. But in that particular case, I was able to resolve it. I did take away as an action it's probably time to start thinking about PagerDuty anomaly detection, that sort of thing. When does alerting happen? When do engineers actually get calls when not just during the normal nine-to-five of the workday? So I'll be investigating that in the coming weeks and see where we get to. But it's sort of the first thing that really pushed us in that direction. The other thing I'll say is we have the idea of the point dev, which I've talked about on a couple of episodes. But the idea is for each week, one individual on the engineering team is in charge of the noise, for lack of a better term. They're looking at the error stream in Sentry. They're looking at any ad hoc requests that are coming from our admin team, et cetera, et cetera. And that's been really great. But one thing that I've noticed is that dealing with the errors is particularly tricky and what we did in this particular case was just to pair on that. As an individual, it is really hard to sometimes to reproduce, sometimes to just understand these are the things you didn't expect in your code, and therefore they are, by definition, harder to understand, harder to think about. And then sometimes you get to an understanding. You're like, ah, what do we do about that? Do we care? Do we not care? Is this just noise? Is this something we should solve? Is it something we should solve soon? Or is this something we can solve whenever we get to it in the backlog? And making that sort of determination is all the harder. And so I'm increasingly of the mind that there should be some amount of time that is pairing on that error backlog to bring two heads together. I hadn't been thinking of it this way, but I've now come around to thinking this is a really great place for pairing because it's so hard for one individual to deal with that complexity to make the hard value judgments. And to do that, if each individual does that in a vacuum, then we have n different value systems at play that are hopefully very similar. But if we start to pair up, then there's osmosis between those groupings. And ideally, we sort of coalesce towards a shared value structure around, like, what can we ignore? What should we snooze for a week? What should we put in the backlog? What should we prioritize and fix immediately? Because I think those are really hard things to otherwise...that's really hard to document, I would say. I would love to write up a page in the Wiki that says, "This is how you treat errors," except each error is a unique snowflake, and you just have to follow your values. STEPH: I have been on teams where we've written up documentation that helps you triage an error because you're right; you can't write documentation around a specific error. But that I always found really helpful where it was like, here's all the links that you can look at, here are some recommendations. When we were working on an application that was falling over more often, there were some specific outlines around if you see this problem, then this is typically how you can solve it. And then we had to fix that at a larger scale, but it was a nice band-aid to get us through at that point. I like the idea of pairing, especially as you mentioned; it's tricky. It's funny when you mentioned capturing those errors and putting them into the backlog because I like that idea that then you can prioritize and bring those into the sprint. It just made me feel a bit hesitant. If we don't work on it now, we're never going to work on it. But then that feels unfair to say because it really comes down to the team. If you have a team that's going to be able to look at those errors and say, "Yes, we're going to bring them in and prioritize them," then that feels really good to then be able to say, "This is an error. Let's capture it. Let's provide some content around it. But it doesn't need to be addressed at this moment. It's still pretty low in terms of risk for users or at least low in impact for users." So yeah, I guess it just depends as long as the team feels good about being able to prioritize errors, which I feel confident that your team would be able to do. And if you can't, then y'all could reassess that plan. CHRIS: That's why we definitely have that. We're revisiting the errors. They're part of the same backlog as everything else. So they're coming up in relative priority and getting worked on and getting resolved. But we're also shifting our thinking just a little bit to say, "We should take a little bit more time in the moment to try and resolve some of these where we can." I have the dream of there are just zero bugs ever. But that's hard, especially in different platforms. And we're seeing a lot of mobile traffic and from different older Android versions and so weird JavaScript edge cases and things like that. Like, why does your runtime not have object? That feels like a thing every JavaScript runtime should have. But that's a joke. Every JavaScript runtime, I'm pretty sure, does have object but that sort of thing. It's like, whoa, this is weird and specific to this one device. Cool, those are fun. So yeah, giving a little bit more time to do those. And again, so we definitely do have the document that describes here are the places to look and how to think about this category of error and this category of error. But at the end of the day, you get one that's just like, there's not a ton of detail in the error. It's hard to reproduce. It might be device-specific, et cetera. And so what do you do in that moment? And that's where we're trying to...I think pairing is a great way to share that thinking around the team. So overall, it's been great, though. I think everyone who has been involved has been like, "This was better than when I did it on my own," so cool. STEPH: Awesome. That sounds great. CHRIS: Yeah, I think so. This is one of those ever-evolving facets of how we work as a team and how we build the platform. So I will certainly report more in future episodes, but for now, happy with that. And yeah, what else is up in your world? STEPH: Yeah. So we've been looking specifically into tooling around how we're going to spin up more machines to process more RSpec tests. So specifically, we have around 80,000 RSpec tests that we are processing, and we have one machine that is parallelizing those and takes around just for that portion of the build because then there are other tests and things that get run that brings it up to about a total of 30 minutes. But for the RSpec portion, I think it's probably around 20-ish minutes to process those 80,000 tests. So we split that across four different containers, and then we run those tests. And so we'd really like to spin up more machines to then process because we've reached the point that we have given as much power to that one machine as possible. So now we're looking to add more machines. And one of those solutions that we're looking at is using Buildkite, which is built with the idea that you can add these build steps so then you can more easily say, "All right, once we get to this particular build step, hey Buildkite, we'd like to run n number of machines to process all these tests." And that seems really nice. And it is something that we are interested in. It is actually what Shopify uses. They use Buildkite ci-queue, which is built for mini-tests, which is what they use, and Redis to then run all of their tests. But we are using TeamCity, so we're not using Buildkite. And we would like to see if we can grow with our current CI infrastructure versus having to move to a new one. There's a lot of just risk involved in moving to a new one. And so we've been studying hard if TeamCity will let us do this. And so far, the answer has been no. But just recently, we found somewhere in the docs that it looks like there is a chance that with TeamCity, we can inform TeamCity that, hey, even though we have just this one build step, instead of only giving us one agent or one provisioned machine to then run these tests, instead that we actually want to spin up a couple of machines to then process these and then aggregate the results back to this one step. So we're looking into that. But I wanted to throw this out there in case anybody else is also using TeamCity and has already invested in this particular approach. I would love to hear about it because we are currently figuring out the capabilities and if this is something that we can stay with our current infrastructure or if we're really going to have to look for a new solution. CHRIS: Well, I'm hopeful that someone out there can give you some input. I definitely get the idea that you're stuck, and stuck is maybe too strong of a word. But if TeamCity is not ideal, the idea of moving off it does feel exceedingly heavy and the riskiness that you talked about. That's, I think, a critical word here because I think it's easy to think of CI as like it's a very important thing. But that's absolutely critical as part of your deploy pipeline, I assume. This is speaking generically about CI, and so it is, in fact, a critical piece of the infrastructure. If you've got a bug on production and suddenly CI is down, what do you do? I guess you can test locally and decide you're going to push past it, but then you have to circumvent it. And so I understand the intentional way that you're thinking about that and the risk associated. I do wonder, though, if TeamCity has felt like not the right platform for a while and if there are considerations. Is there the possibility of both trying to improve the world that you have now, so it's not the big move off of it but then also in parallel start to work on an alternative implementation? This is perhaps not entirely fair, but it feels like a Rails application is this repository of code. And typically, CI is configured via a file. And that's like, if you've got your teamcity.yaml or whatever it happens to be, could there also be a buildkite.yaml that is not on the critical path for deploying or anything like that? But it is a way to, frankly, somewhat inefficiently test on two different platforms but start to see if you can get the code moving on a different platform and be able to gradually build out and make that transition possible without it being one big swap over sort of thing, which eventually it would need to be. But just wondering, is that happening in parallel? Is that a possibility? STEPH: I think the short answer is, I'm sure there is. There's a way to look at the existing system and then find ways that we can tweak it. But I also know that the team has already invested a lot into working with the current system and making it as efficient as possible. So I don't know if there's any true big impact but intermediary steps that we can take. We are definitely in that proof of concept world. So we're not going to move anything over for the rest of the team until we can really prove that something is working for a small subset and then start to expand from there. But currently, our idea is to dig further in TeamCity, which I think also includes just a call to their team and say, "Hey, we'd love to talk to one of your engineers and see if the thing that we're trying to do if it's possible. Let us know if it's not and if we need to look elsewhere," which is intriguing to me because having a lot of tests isn't new. There are tons of companies that have lots of tests, and they want their CI test suite to be fast. So a company that then has built software that helps Team execute these steps that then the ability to say, "Hey, I want more machines to process. I want to give you more money and to give us more machines, and we can process more things." I feel like that should be a thing. And I'm getting at the edges of my knowledge. This is why we're exploring all of this. But it has been surprising to me to realize that that doesn't seem as easy of a thing as I would have expected it to be. There are also some other concerns around here where the client that we're working with if we're going to work with third-party vendors, then we have to get special approval to work with them. It's not just a hey, we can just go try it out. It's a lengthy contract process that we'd have to go through. So there are also some constraints that we have to keep in mind where we can't just work with anyone. We need to be careful to make sure that they're certified in a particular way. So yes, I like your idea. I will definitely keep it in mind. But I don't know if there are any true intermediary steps yet other than the building out a proof of concept and then finding small ways that we could move over. Then I think that would be ideal for sure. And then hopefully, if there's anybody that's listening that has experience with TeamCity or Buildkite, that's the other tool that we're looking at using, let me know. I would love to chat about it and find out your experience. On that note, shall we wrap up? CHRIS: Let's wrap up. The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

The Bike Shed
328: Terrible Simplicity

The Bike Shed

Play Episode Listen Later Mar 1, 2022 52:36


Chris is helping with efforts to introduce security, practices, and policies at Sagewell. Right now, they are refining the usage of 1Password to standardize passwords and secure information. He also shares (what he believes) is a terrible idea around fixing inconsistencies around symbols and strings. Steph shares an update around factories. Also, at Sagewell, Chris is helping to build mobile apps, one for iOS and one for Android, and is considering pursuing having them be all native. Good idea? Terrible idea? Chris and Steph riff on that a bit. This episode is brought to you by ScoutAPM (https://scoutapm.com/bikeshed). Give Scout a try for free today and Scout will donate $5 to the open source project of your choice when you deploy. Services down? New Relic (https://newrelic.com/bikeshed) offers full stack visibility with 16 different monitoring products in a single platform. GitHub - alassek/activerecord-pg_enum (https://github.com/alassek/activerecord-pg_enum): Integrate PostgreSQL's enumerated types with the Rails enum feature Feature #7792: Make symbols and strings the same thing (https://bugs.ruby-lang.org/issues/7792) - Ruby master - Ruby Issue Tracking System RailsConf 2016 - Turbolinks 5: I Can't Believe It's Not Native! by Sam Stephenson (https://www.youtube.com/watch?v=SWEts0rlezA) GitHub - hotwired/turbo-ios (https://github.com/hotwired/turbo-ios): iOS framework for making Turbo native apps Become a Sponsor (https://thoughtbot.com/sponsorship) of The Bike Shed! Transcript: CHRIS: Weird stuff happens when we sing, Steph. STEPH: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Steph Viccari. CHRIS: And I'm Chris Toomey. STEPH: And together, we're here to share a bit of what we've learned along the way. So, hey, Chris, what's new in your world? CHRIS: Hello, Steph. What is new in my world? We are continuing with some of the efforts that we're doing to introduce security, and practices, and policies, and all those fun sorts of things at the organization. One of the things that this is pushing on is we are further refining our usage of 1Password at the company as a way to standardize passwords and secure information and how we store that, how we move it around, as well as integrating SSL, and all those other fun fancier things. But I'm personally historically a LastPass user, and now I'm getting to experience 1Password. So now I'm a child of two worlds, and it's terrible, and I hate it. I hate every moment of this existence. So what I need to do is move over to 1Password, but now I'm in that space where I'm like, I can see the flaws of both systems. This is terrible. I don't like it. 1Password does seem to be great; I will say that. There's one really interesting thing about 1Password. I'm interested...you're a 1Password user, right? STEPH: I'm not; I use LastPass. I'm also a child of two worlds because we use 1Password for thoughtbot stuff, but then I use LastPass for my stuff. CHRIS: Gotcha. Okay, so you survive in the middle space. I'm slowly trying to move everything over because I think 1Password has a little bit more of what I'm going for. And I would like, frankly, to be in one cohesive, consistent space, although having two different accounts seems interesting. I definitely can handle it. But knowing which I'm in and how to save a password to one versus the other, it's a whole thing. The one thing that I find really interesting though is 1Password has a feature where it will do two-factor, two-factor authentication. It will do that for you. Specifically, it's doing, as far as I can tell, the TOTP. I don't know what that acronym stands for, but it's the fancy type of two-factor, so not SMS, not text message-based, and not others like WebAuthn is a thing that I've heard of, which I don't know if that is distinct from YubiKey or hardware keys. So there's a bunch I'm trying to learn about this space a little bit more. I'm very interested in the hardware keys because those seem cool. WebAuthn seems like a new standard. That sounds cool. Don't know anything about it, though. So mostly, I know about SMS, and I do not like that one. I do not want to use text messages because, as far as I understand it, they're not super secure. So that's not the space I want to be in. But the TOTP, the Google Authenticator, or Authy, or that space of password or two-factor code generation tools those seem good. And 1Password has a feature where they're like, hey, yeah, sure, we'll have your password and your two-factor. And so they grab the QR code, which is typically the QR code is a way, as far as I understand it, to share the seed. And then, that seed is used by an algorithm to generate the current code value for a given point in time. So it takes like, given that seed and the current timestamp, we will generate you the relevant code, which can then be verified on the far side. But that seed only exists for one moment in time, et cetera, et cetera. But I've always thought of it as this separate thing. The idea of having that all in one system is interesting and kind of scary to me. But as I think about it, I'm like, if 1Password or LastPass, in either case, gets compromised, we're all done. Like, this is over. We should throw in our cards, give away the internet. This whole experiment has failed is my sense. But it was very interesting because I had not seen this. I've always had these as separate systems. So for me, I have had LastPass, and I have Authy on my phone for the two-factor. But it's frankly very clunky, and I don't like it. And the 1Password thing is fantastic where I say like, yeah, 1Password, fill in my password and username, and then also fill in my two-factor because you have it. This is great. But, and this is where I hesitate, and I don't know, I will say this: I trust that 1Password has thought about this deeply way more than I can and have come to a place of deep confidence that this is a fine and okay thing to do. But I'm still intrigued. What's going on here? STEPH: That was a lot. I have so many thoughts. [laughs] CHRIS: Sorry, that was a lot of words, a lot of ideas, a lot of space there. It's just where I'm at. STEPH: People couldn't hear me, but I was laughing when you were talking about LastPass or if these accounts get hacked in. And I'm imagining someone who uses the combination of their cat's name and their birthday as their password and then like, aha, I win. [laughs] It's like, no, we just all lose. [laughs] But that amused me. Going back, you talked about having it all in one place. And that actually doesn't surprise me that we're different in this area. Because you also like all of your email...you like one source of everything, which makes so much sense, but I'm different. And with these accounts, I like that I have the distinction between all of thoughtbot is in 1Password while all of mine is in LastPass because it's just a very clear delineation between those two accounts. And I'm sure both of these platforms have figured out a really good way to then separate those two. But I just remembered there was someone at thoughtbot that accidentally...because they have everything in 1Password, they accidentally shared their personal vault with a client. And so they were just typing in Slack. They're like, "Oh, shit, oh shit, like, how do I undo this?" And we're all just watching like, "We don't know. But please let us know how it turns out." [laughs] It turned out fine. I think they actually realized they hadn't fully shared it but based on the UI they thought that they had. So it all turned out okay. So that just lives with me. I'm a little scared of that now now that I know that story. So watch out, friends. CHRIS: Oh, wow. Well, now, yeah, I'm also now scared of that. I wasn't, but now I am. STEPH: And I forgot the other thoughts now. Those were my two main thoughts based on the journey that you've shared. CHRIS: Particular to the thing you were sharing there, yes, now I will have nightmares about it. But also, it feels manageable because they're both entirely different accounts, and then also within that, there are different vaults. So as I'm building up the password infrastructure at Sagewell, there's going to be different...like, the dev team will probably have one vault and then a shared vault for the dev team. And then other teams within the organization will have that. And so it feels like there are at least structures within the tool to manage that. But mostly, my consideration is around the two-factor thing. And like, is this reasonable to do? And again, I'm sure 1Password has thought way harder than I have about it. And I trust that they're like, yeah, this seems fine that they're not just like, I don't know, it doesn't seem bad. They're like, no, no, definitively for information-theoretic reasons, this is fine. But it was surprising. STEPH: That was it. The other comment that you made about two-factor auth that resonated with me because there was a point not that long ago where we have one of those, either New Relic or I forget which account it was, but it was with the systems. We really only needed one person to have access, but every now and then, someone else may need to access that account. And so we wanted to be able to store it in 1Password or LastPass somewhere like that. But then the two-factor auth was a problem because then you had to coordinate with that other person to say, "Hey, I just need to check something. Would you let me in?" And because we could then leverage that feature, then we could just store all of it. And then that person could just go to 1Password or LastPass and then have access to all of it, and that was really nice. That was a very nice solution to I want to say it was a small problem but yet also very important for team happiness. So that was really nice. CHRIS: The amount of times that I've been like, "I just tried to sign in to the shared account, and it says that it sent a two-factor request to somebody's phone, but it didn't tell me whose phone. And I'm not sure if we know who that person is or if that person's still around," that version of the story feels true. And so, the idea of being able to centralize two-factor seems great. It almost feels too good to be true, is perhaps where I'm at. I am putting on my tinfoil hat, and I'm saying, yeah, but oh man, security, though. And again, I will 100% defer to 1Password on this. They've thought about it. But it's mostly I want to get to the place where I understand the thought process that they went through to decide that this is perfectly fine because they definitely did that work. I'm certain of that. I just want to read a white paper or something, and I haven't found it yet. [laughs] I'm like, let me get to that deep place of trust because that's what I want to be at with security tooling and those sorts of things. STEPH: Yeah, I haven't looked for something like that, but that sounds...I'm kind of surprised that doesn't exist. CHRIS: Oh, it quite possibly exists. I haven't done much of a search, frankly, at all. Mostly, I'm in the space of like, huh, that's weird and then moving on with my day. Because there's not a lot of free time to go search for the white papers on the internet. But yeah, so moving from 1Password or LastPass or 1Password, or maybe I'll just end up with both for a while. I really hope I don't end up in that space, although you're describing it as a positive, so maybe I will. STEPH: I have found it helpful for me. When you find that white paper, because you are more likely the type of person to read that white paper than I am the type of person to read it, then I would love a summary. That would be much appreciated. CHRIS: I'm so intrigued by the persona that you're describing of me of; like, you're the kind of person who would read a white paper. I'm like, well, I don't know if that feels true or if it's definitely true or definitely not true. But if I do happen to find it, and especially if I happen to read it, [laughs], I will share it with you and perhaps with the listeners as well. Let's see, one other small thing. I have a bad idea. I don't want to share the bad idea with you. I want to more share it with the audience, and then I want the audience to tell me exactly how bad of an idea it is. STEPH: [laughs] CHRIS: Because I'm sure it's a bad idea. I'm just not sure how bad. STEPH: I love that there's not even a scale of goodness here. It's just nope, this is terrible, but I don't know how terrible it is. [laughs] CHRIS: What's fun is in the later parts of this episode, we're going to go into a segment of good idea, bad idea, sorry, good idea, terrible idea because I like that framing. No, this one is firmly bad idea, but how bad is the question. So we're working on the app, and we keep running into inconsistencies around symbols and strings. As any Rubyist who has worked in the language for any amount of time, especially in a Rails app, you have experienced this unpleasantness. There are strings; there are symbols. They're often used somewhat interchangeably, and yet they're different. You'll hit bugs. You'll hit edge cases. You'll hit nils that you didn't expect to be there because you tried to fetch a symbol. It, in fact, was a string, et cetera. So, what if we just applied HashWithIndifferentAccess everywhere, just deep in the internals of the app or in the Ruby runtime? What if we were to just turn this on? My sense is this would be terrible for performance reasons. My understanding is that's why symbols exist is because they are a more performant mechanism. Strings are complicated within the object model of Ruby because they're mutable. These are things that I understand very loosely, as you can tell by the tone of voice that I'm using. But symbols and strings they're separate. They're separate for reasons, performance I believe to be the main reason. But what if we were to just say, well, what if it could be like easy, though? That's what I want. Like, this is the promise of Ruby is that I want to express my code in a way that feels like the words I would use to describe to another human. That's the way I always think of Ruby is it's as close to the words I would use to describe the sort of business logic as possible. And yet these symbols versus strings thing it's just annoying, frankly. And again, I think very good reasons for it, I'm sure. But what if we were to just do the silly thing and turn on HashWithIndifferentAccess for everything? I don't even know that that's fundamentally possible. I don't know that there's the relevant hook or the way to do that. But I would love that because we're using it somewhat regularly throughout our app right now, where we're getting data from one API. And in our test suite, it's one way, and in our code, it's the other way. And granted, that speaks to us being inconsistent in our usage. But overall, I would just love for this to not be a thing. And so, how bad of an idea would it be? How much of a performance hit? That's my guess as to what it would be. Maybe there's actual fundamental correctness that would go wrong here. But my sense is by collapsing the space together; we would actually get more correct. I don't know. Anyway, how bad do you think of an idea this is? STEPH: I was thinking through some of the bugs that you're running into. And I think you provided some nice insight around that around it's the fact that you're fetching data from API. So it's typically you're parsing. That's how you're getting the string and symbol differences is because when you're parsing JSON and then you have a mixed case of maybe you have a symbol, maybe you have a string, or maybe you're parsing it differently. Are there other places in the application where that's a concern? CHRIS: I want to say one other place that we're running into it specifically is we're using a lot of enums, particularly ActiveRecord::PGEnum backed enums. So these are Postgres enums at the database level. And then, within our Rails models, we define them as enums. And the enum is typically defined within the model as a mapping of symbol to string. It could be symbol to symbol. I'm not even sure. I think this might be in terms of our implementation. But you say like, it's an enum. The key is foobar with an underscore, and it's a symbol, and then the value is foobar, but it's a string. And maybe both the key and the value could be symbols; maybe that's a thing, maybe this is our fault. But certain times, when you're interacting with the value, it's a symbol. Certain times I find it to be a string. I feel like that's true. I don't think I'm making that up. [laughs] It's possible I'm making it up. But that's another place where I feel that inconsistency or other values within the system that like as they go through certain type coercion layers, they'll start as a symbol, and then they get saved to the database, and then they get reflected back, and they come back as a string. And it's like, well, that's unfortunate. It was a symbol a minute ago, and now it's a string. And so our tests suddenly break in this way, or our code is inconsistent. And it's enough of a nuisance that I had the bad idea the other day. And so, I wanted to bring the bad idea to this space. STEPH: I think you're right. I think the main reasoning for not having everything just be strings is for looking for that performance benefit. And so then using that HashWithIndifferentAccess then you'd have to loop over everything and then convert it. So I imagine, like you said, there would be a performance hit there. I don't know how bad of an idea it would be. But when you said this, it brought up a memory because I remember someone proposing or the Ruby community talking about the fact, like, what if we didn't have strings? What if everything was just a symbol? Or can we just have one over the other? And there is a ruby-lang issue; it is 7792. And we shall also put it in the show notes and send it to you. [chuckles] And this person is proposing make symbols and strings the same thing. And then some people call out specifically the idea of using HashWithIndifferentAccess and saying, yes, that works wonderfully, but then you are going to have a performance hit for it. So it sounds exactly like everything you're saying. I don't know the outcome. I mean, clearly, the outcome is we're not there. But it seems like a really good place to see the reasoning or different approaches that maybe people have tried in this space. CHRIS: Ooh, I love that. I definitely want to read that and see what sort of deeper thinking folks have done on this. Because again, this feels like another one where definitely folks have thought about this, folks who know more about it and have chosen the current path that we're on for reasons. But I would be really intrigued if I could be like, yeah, I would just like it to be easy to start, and then have the performance optimization be something that I could opt into. Again, that's probably not tractable within the language. Like, oh, we have a hot code path here that we want to actually have immutable symbols only. And that's the sort of thing if we've done this HashWithIndifferentAccess everywhere, you can't back out of it. And so, therefore, you're stuck in a performance low point. That feels like a bad case. And so maybe that's the reason is like, you will shoot yourself in the foot with this definitely. But yeah, I'm intrigued. So I will definitely read what you're sharing here. And we'll include it in the show notes, of course. I'm probably not going to do this, just saying that out loud because it seems like a bad idea. I just want to know how bad of an idea. STEPH: I do love it, for when I'm building a class that's working specifically closely with an API, I do reach for HashWithIndifferentAccess frequently. Because like you said, I just don't want to worry about it. I want to set it up top. It's one of the rare times that I actually will use something in an initializer where I'm like, hey, pass in the data. I'm just going to run it through this method. And then all the data from here on forward you can access it in either way. So the class doesn't have to care; a tester doesn't have to care. So I do feel your pain, or I at least will always reach for it whenever I'm building a class specifically around interactions with JSON. CHRIS: So for a segment that I framed as how terrible of an idea this is, you're like, hmm, I don't know how terrible. That seems to be your take, which is interesting. STEPH: Good point. Let me assess for a moment. I'm going to go just from skimming this issue, although I think partially this issue is talking about the fact that if you merge symbols and strings, it's like, hey, friend, you're going to break a ton of stuff and break a bunch of libraries, and these two things do serve a purpose. So this may not be exactly what you're looking for, but it has some interesting conversation on there. But embedding it deep down in the app so that just happens naturally sounds like it's just a performance concern. So yeah, it comes down to what is the question? How big is the performance? So I feel like I can't say it's a terrible idea until I actually know what the performance hit is. CHRIS: So a plausible question. That's where we're going to put this in the category of. [laughter] STEPH: Plausibly terrible, but still worth researching. CHRIS: Not obviously not terrible. But anyway, these are some of the ideas at the top of my head right now. That's a rough summary of my week. Mid-roll Ad Hey, friends, let's take a quick break to hear from today's sponsor, New Relic. All right, so you've probably experienced this before where you're just starting to fall asleep, and it's a calm, code-free peaceful sleep, and then you're jolted awake by an emergency page. It's your night on call, and something is wrong. But I have some good news because you have New Relic, which means you can quickly run down the incident checklist and find that problem. So let's see, our real user monitoring metrics look good. And that's where New Relic measures the speed and performance of your end-users as they navigate the site. But it looks like there's an error in application performance monitoring. If we click on the error, we can find the deployment marker where it all began, roll back the change, and, ooh, problem is solved. We can go back to bed, back to sleep, and back to happy. That's the power of combining 16 different monitoring products into one platform. You can pinpoint issues down to the line of code so you know exactly why the problem happened and can resolve it quickly. That's why more than 14,000 other companies, including GitHub and Epic Games, use New Relic to improve their software. So you know that next late-night call is just waiting to happen, so get New Relic before it does. And you can get access to the whole New Relic platform and 100 gigabytes of data free forever. No credit card required. Sign up at newrelic.com/bikeshed. That's newrelic N-E-W-R-E-L-I-C .com/bikeshed, newrelic.com/bikeshed. STEPH: I have an update that I can share around factories because the last time we were chatting, I was sharing that strategy that we're pursuing where we're trying to minimize factories and then speed up the CI time by reducing the work that those factories are doing. So Joël Quenneville has done some phenomenal work and this past week, specifically improving factories. And he found one particular factory that he was digging into. So some stats before the change. The factory was taking around two seconds, which I know on paper doesn't sound so bad, but it gets more interesting. So total database time is around 1,000 milliseconds. And 833 total database queries were being made, which includes reads, creates, and updates. So then after, Joël was diving into this looking mainly to reduce the number of database queries because that's such a big number. So after the change, which took a lot of research on Joël's part, the factory is now taking around one second, so half of that time. The total database time is around 666 milliseconds. And the total database queries went from 833 down to 647, so a nice improvement there. But the real wonderful outcome of the story is not just those stats, but okay, so how did we impact CI? So we spent time working on this factory. And we have reduced, and we can see some of that in the stats. But how does that apply to the bigger picture? And so Joël took the time of the last 20 successful builds, and based on those builds, we average 27 minutes and 37 seconds for each build. With the factory change that he made, that same test suite was now averaging 21 minutes and 33 seconds. So shaved off six minutes from the build time, which is about a 22% decrease in the build time which is just fabulous. So that was a really nice win from all the work that had been invested in improving that one factory. CHRIS: That's a heck of a haircut there so glad to see that the efforts are paying off. STEPH: Yeah, it was a really nice win to see that we had researched which factories we should pursue, and then we were methodical about that. And then Joël worked hard to improve this factory and saw such a large payoff. It's one of those areas where the team has already invested a lot of effort and hours into improving the test suite. And it's challenging when you have so many areas that you'd like to improve and 100-plus engineers also contributing to that same codebase. So how do you improve and keep up with it all at once? They had spent about a year, so I think they were recognizing that yes, there are still a lot of areas to improve but also felt like small efforts wouldn't move the needle. So it was a nice data point to remind ourselves that we can still reduce the CI build time in a significant way. We just need to be very strategic about where we invest our time in those improvements. There is also an interesting conversation that Joël and I were having because we have a daily sync with each other each day. We've now been embedded with a team with a client, which is wonderful, but before then, we were also chatting with each other. And we like to chat about code, so we've had lots of fun conversations around code. And one, in particular, this week, came up about how people view code differently. And there's even a tweet that Joël shared that I can link to in the show notes. And there's one view that code is a liability, and if a line can't justify its existence, then it should be deleted. And then there's another view that code is an asset. If a line isn't causing any immediate issues, then why not keep it? And part of the reason that came up was while I was going through and reading pull requests, there was a particular change where someone was memoizing an expensive call, which was great, something that we wanted to do. But then they were also memoizing a very fast operation in two other places where it was just like parsing some params something that, you know, superfast and only getting called in maybe two places. And it was one of those that just caught my attention to be like, hey, I love that you memoized this other call, but this one, I don't think we need the additional overhead or complexity of adding memoization. And I found myself when I was writing that suggestion for the author that I was already looking for more than just to say, like, hey, this is more than we need. Because I've realized that often I take that stance of code is a liability. So if we don't need it, let's just get rid of it. But I've definitely run into other people where they're like, well, it's not hurting anything, so why can't I just leave it? And getting that kind of pushback on suggestions about removing code. So it was a fun opportunity to think through okay, well, why is this memoization not just unnecessary, but how could it actually cause us problems? And what's the cost of keeping it in, not just the cost of removing it but also the cost of keeping it in? And that was fun to talk about. CHRIS: I'm so glad you're bringing this particular conversation up because if we're being honest, I saw Joël tweeted about this. I saw it. I sent an email to myself linking to the tweet with the subject of the email being ahhhh, just A-H-H-H-H, which I believe was me being like, oh my God, we got to talk about this. I apparently didn't want to write all of those words, so I just wrote ahhhh. But as a handful of asides, one, if you're not following Joël Quenneville on Twitter, @joelquen, that is a mistake, because Joël is one of the clearest, most concise, and effective thinkers about code that I've ever seen. The writing that Joël produces is absolutely fantastic. And having worked with Joël for forever, I still will look at his Twitter feed and be like, well, this is fantastic. You're saying amazing things that I have not heard you say. So, again, strongest recommendation I can make; please follow Joël on Twitter and also via the Giant Robots blog and all of those other places. But in particular, I saw this one come through, and I was like, oh, man, we have to talk about this. So I actually have it up in my email app right now behind the scenes. [laughs] I was like, oh, I want to mention this to you, Steph. So I'm very excited that you're bringing it up in this moment. It is such an interesting thing. It's such an interesting case of like; I deeply believe both of these truths, and yet they do seem to be in contradiction. And so what do we do with that? More generally, I feel like that's true of a lot of stuff in life, like, the ability to hold two competing ideas in your head and be able to know where one applies and where one doesn't. That is a critical thing to get to in life and to figure out how to do, and that's some of the hard work of thinking. But in particular, this one, the idea that code is a liability. You have a line of code...I'm going to read it precisely as Joël wrote it, "Code is a liability. If a line can't justify its existence, it should be deleted. Code is an asset. If a line isn't causing any immediate issues, why not keep it?" And I think for me, if I were to try and interpret this, because I do believe both of those sides, I would apply one during code review. When code is coming into the application or when I'm writing code, do I need this? Do we need this? Is this necessary? Because it really should be necessary to come into the app. But then once something has made it in, especially the longer something's been in there, I think code sort of ages and matures. And so, the longer it's been part of the app and not causing an issue, the more I am liable to just leave it at rest. Just say, sure, or not at rest but as part of the runtime production code. But these are two competing ideas, but I think they apply at different times in the conversation. And so I'm definitely on memoization. In particular, memoization is a form of caching. Caching I have run into a handful of caching bugs in my life, let me tell you. I'll probably run into a few more. So if we can avoid caching, let's do that. So that's a particular question around that thing. But again, that idea of like the point in time to have that conversation is during code review or initial authoring or when it's about to come into the app. But if we've had some memoization in the app for forever and you're like, do we need this memoization? I don't know, but don't remove it because maybe it's very important at this point. Maybe it's one of the cornerstones holding up our application. So that's a bunch of thoughts about that. But also super glad that you brought this up because I was very excited about this particular tweet. STEPH: Yeah, there's someone that said something very similar to what you just said around they agree with number one for all new code. And they agree with number two, where code is an asset for refactoring. And I thought, yep, that's a great way to look at it. And I hadn't really thought about that specific perspective. And so it was one of those moments. Because I do like when people will push back on something that I so firmly believe on, not that this person did. I was, frankly, having a conversation with myself based on previous conversations with other pull requests authors that I've had that it's not related to this particular pull request. But in general, when people do push back on something that I do have such a firm belief in...and early eager optimization around memoization is something that I'm just like, I don't want to do it, especially for something that's so cheap and in such a fast execution and something that we're only calling twice. There's no benefit to it at that point. But then when someone says, "Well, but it's not hurting anything," then I appreciate that question because then it's more of not just pushback, but it's sort of well, tell me more. What is the pain that I'm introducing by keeping this in? And then that can be a really nice conversation to have with someone around; like you just said, I've seen caching bugs, and this could be a caching bug, and they are painful to then triage. And so we've introduced this optimization, but it's actually just going to cause us debugging pain later. And we really didn't even get the reward from it in the first place. So I really like those conversations when I feel like there's a little bit of a challenge of where I'm like, oh, I hold this as a deep truth, and somebody doesn't, and I would like to have that conversation with them. There are also some other fun conversations; one was around introducing a query object, which, as you know, we're both really big fans of. And then there was another great question because not everybody who works on this team is really familiar with Ruby and RSpec. They work in Scala, but then sometimes they hop over to the Ruby side. And so then they hop into the Ruby channels, and they're asking questions. And one of them was around the idea of introducing an RSpec Matcher. And they're like, "Am I doing this right? Is this how you would extract something to then improve your test? " And so that was a really fun conversation around like, yes, you did it right. This is exactly how you write a Matcher. But let's talk about use cases because extracting something to an RSpec Matcher to me means it meets the most generalized sense of usefulness that you want the whole team to use this and that you're willing to put in the extra overhead to then introduce this essentially like new RSpec DSL for the rest of the team to use and then maintain that. So it is the most aggressive step that I take when I'm trying to introduce a helpful tool. So then I shared my progression for when I'm extracting something for a test. And first, I will start with just a local method to that test because then it's scoped to just that test. And from there, then I will think about extracting to a shared helper. So maybe it's a module that can get included. But then its scope can still be confined to a couple of tests, but then we've also increased some of its observability. So then other developers will notice it and be able to share with it. And then from there, if I'm like, oh, this is super generic, it is testing time, and it's something that everybody is going to benefit from, then I reach for something like an RSpec Matcher or introducing a custom RSpec Matcher. So lots of fun testing conversations this week. CHRIS: That was a wonderful hierarchy. I like that a lot. I feel like that would make a good blog post. STEPH: There are some things that I realize that I just think of inherently about that I realize that would be fun to share. I'm much better at podcasting than I am at blog posting. [laughs] CHRIS: There's this friend I know, Joël Quenneville, very good at the blogging. He could probably help talk you through writing this up as a quick blog post. But you just described this heuristic hierarchy that you have. And you could probably provide quick examples of each, and I think encapsulate that knowledge. I, too, default to podcasting because it's easy for me to just say stuff here, and then it's there it is. But what you just said also mirrors exactly what I would think of as sort of the hierarchy and the reasons you're like, I'm not sure I'd go all the way to an RSpec Matcher. That hesitation is meaningful and comes from experience that you've had. And again, that seems sort of a trade-off of like, well, why not? Is it hurting anyone? What's the cost here? You know that cost. You have that in your head. And so now if you can capture...I don't want to put work on your plate. But I think that would be a great blog post. I would be happy to read that blog post and share it with other folks. STEPH: Cool, cool. Cool. So I totally hear you. So here's my hierarchy. Typically, I start with a podcast, and then I share it there. And then maybe it'll go to a tweet. And then once I'm like, okay, this is super generic, it can help everybody, then we've reached blog post status. CHRIS: I love how tweet is higher in the hierarchy than a podcast for you. That somehow the throw away let me just have 140 characters or 280, or whatever we're at these days, that somehow that's next in your hierarchy. But I agree; I share that place in the world. STEPH: Yeah, just writing is hard. Here I get to show up, and I say things. And then we have wonderful Mandy, who is then editing all of our words, so there's a safety net here. If it's just me and a keyboard, who knows what's going to happen? CHRIS: Then you'll probably think about the switches that you're using on the keyboard. And do you need a new keyboard? Should it be silent? What do we do? STEPH: I was thinking more how many exclamation marks do you use? That's always a question. CHRIS: Not too many, not too few. It's a difficult question. STEPH: [laughs] Mid-roll Ad Hi, friends, and now a quick break to hear from today's sponsor, Scout APM. Scout APM is an application performance monitoring tool that's designed to help developers find and fix performance issues quickly. With an intuitive user interface, Scout will tie bottlenecks to source code, so you can quickly pinpoint and resolve performance abnormalities like N+1 queries, slow database queries, and memory bloat. Scout also recently implemented external service monitoring, adding even more granularity when it comes to HTTP requests and API calls. So give Scout a try today with a free 14-day trial and experience first-hand why developers worldwide call Scout their best friend. And as an added bonus for Bike Shed listeners, Scout will donate $5 to the open-source project of your choice when you deploy. To learn more, visit scoutapm.com/bikeshed. That's scoutapm.com/bikeshed. STEPH: Pivoting just a bit, [laughs] what else is going on in your world? CHRIS: What else is going on in my world? So we are building out a whole platform over here at Sagewell, and one of the things that we need to build is a mobile app or, frankly, two mobile apps, one for iOS and one for Android. And I'll be honest; I resisted this for a while. I am a big, big believer in the web as a platform like deeply in my heart of hearts. That's the place that I want to spend my time. That's the thing that I believe in. And there are absolutely cases where truly native mobile apps shine, completely outshine what we can do on the web platform sometimes for reasons that are, I think, not great, limitations of the available mobile web platforms, et cetera, reasons that I'll slam my fist on the table or whatever it is. But there are plenty of really great mobile experiences, offline, et cetera, that we just can't...offline is not even a great example. See, I can't even find a great example. There are definitely things, though, where truly native mobile apps are 100% superior. But again, I'm such a big fan of the web platform that that's what I wanted to do. I wanted to hold on to this dream of, like, what if we just make a really great web app and it's just great? And then consistently, our backend is one singular thing. Our frontend is kind of one singular thing. And yeah, we got to deal with responsive design. But that's to me a much more tractable problem than fracturing our entire application architecture across a bunch of different platforms and having all of the logic of our domain splintered and especially depending on how you implement it. That's sort of a big question. I've talked a ton about Inertia.js on this podcast, and that's because I believe it's a really great example as to how to pull some of the logic back to the server-side, which, in my experience, that's where I want the logic to be implemented, our deep domain logic. I just want that to be on my server in a Rails controller, or a Rails model, or a command object, or any of those sorts of things, query objects, all of these wonderful things but server-side that's centralized in one space. Nonetheless, though, we had to build a mobile app. These are the truths of the world. Sometimes it just comes down to the expectation of your user base. And there are certain things that by building a mobile app we will get so, for instance, in our case, having biometric login, so fingerprint, or facial ID, or any of those sorts of things. Those are actually material security differences. They are actually, as far as I can tell, available on the web but not consistently on every browser, et cetera. So that's something that we can get by having our app as a native app. Push notifications is another one that certain platforms, certain web platforms have dragged their feet on, Apple Safari. iOS Safari, specifically, I'm looking at you, but that's an example of something that by going the truly native route, we'll get that. Similarly, access to some of the lower-level things, cameras, et cetera, that is something that we'll get a better experience of. And again, you can hear in my voice I don't want to really seed it to the native platform, but it is true right now, at a minimum. So we had a decision to make as to how we would implement these applications, and we went with an interesting route. So for anyone that's familiar with Turbolinks native, or I believe Turbo iOS is pretty similar. But I'm more familiar with Turbolinks native as there was a talk I Can't Believe It's Not Native I think is the name of the talk that was given a while back talking about the Turbolinks native architecture. So basically, what's happening under the hood is let's still render these things server-side. Let's send down some HTML. In our case, it's a weird sort of hybrid of HTML and not HTML. But broadly, let's say that the server is rendering things. And our native application is going to then be a native shell that wraps around WebViews. But it does so in not just a single WebView sort of way. It's instead trying to find that optimum hybrid spot where let's do native things where they make sense. So, for instance, we have introduced a tab bar at the bottom of our application that is a truly native UI. We similarly have push notifications, biometric login, et cetera. Those are features of the native platform that we're using. But then, for most of the screens, most of the screens that are just some text, maybe a button, maybe a form, et cetera, we are using the server-rendered code that we have. And so server-rendered, in our case, because we're Inertia, it's sort of a misnomer because technically it is being rendered on the client-side in the WebView. But, I don't know; we're now getting too nuanced and in the weeds for it. But what we've opted for is to reuse the same views, controllers, et cetera. All of that is still being reused. Our iOS and our Android codebase at this point are wrappers around those WebView stacks. So it's not just a singular WebView; it's a stack of WebViews. So if you're doing swipe to navigate thing on iOS, that'll work...or Android. I think Android has an actual back button, though, within the applications. But most importantly, we've introduced a tiny little bridge layer. So from our WebViews, we can communicate to the wrapping native context. And similarly, from our native context, we can send messages into our WebView. So we can have a button in our native UI. And when a user clicks that button, it will send a message to the WebView that it's wrapping around and vice versa. We can do push notifications. We can do all that sort of stuff. For any given view, like, say, the login view, we can say, "Hey, don't render the normal server-side thing. Instead, render this truly native, local Swift or Kotlin view that we want to use there." So it's an interesting choice. I think it's something that I've certainly seen applications that are just like, let's take some HTML and wrap it in a WebView, and it'll be fine. And they don't make great apps. But I think this time it might just be a good idea. I actually do think that the approach that we're taking, at a minimum, is buying us a ton of simplicity in terms of having to duplicate what are somewhat nascent domain concepts across multiple platforms. We're not entirely certain as to what our platform and what our business is going to be. So we'd love to non-enshrine that across three different platforms that are hard to update. Like the web, I can kind of change that every day. But iOS and Android because I have to go through review cycles, because I have to get them out to devices, because there are slow update cycles that individuals will use, I'm going to be stuck supporting whatever version of these applications are out there. And so if more of that is the dynamic content that's driven by the server, frankly, I just feel way better about that, at least for now, at least for the point in time that we're at. But I kind of believe that this may be a really useful architecture for us long term. That was a bunch of me rambling about the architecture. Let me pause there, thoughts, questions, comments, concerns? STEPH: First, I really appreciate the thoughtful approach and explanation. Also, you highlighted the reasons that y'all are pursuing having a native app, and all of that makes a lot of sense. Because there is that user expectation of you told me about a service that then there must be an app that I can download because that's what I'm accustomed to using versus having to go to a browser and then having to then remember the URL of the site that I'm supposed to go to. So there's that convenience factor. There's also the idea that some people go to the App Store and search for their solutions instead of going to a browser and searching for a service. So having that presence in the App Store can seem like a really huge win because then even if it maybe slowly pushes them back to use the website or as long as they get a decent experience, they've now at least been exposed to the idea of the service and that it's out there. But then, as you pointed out, building a mobile native application is a lot of work. And then it becomes a question of like, well, are you going to hire people to work specifically on these platforms? And then, is it really worth that investment at this point? Or is it worth the approach that you're taking where you're going the more hybrid approach? I am curious; maybe this is something that you'll know. So as you are investing in this hybrid approach and you are starting to collect more users that are then using the app versus going to the browser, then what does that pivot look like, or how does that further investment look like? If you realize that the UI isn't quite delivering the expectations that you want that if you'd actually built a native iOS or Android application, then what does that investment look like? Can you still reuse some of the work that you've done? Is it totally scrapping that work? I think that would be my biggest question around taking this first approach. Is it an all-in bet that we are now stuck to this? Or is there some salvageable pieces to then move this forward into native apps should we need to do that? CHRIS: That's a heck of a question. Have you made a terrible decision or just like an iffy decision? I think that the framework that we're choosing or, frankly, building right now will actually be amenable to a potential transition entirely into the native world in the future. So again, one of the options that we have here is the ability to say, no; this facet of the application is entirely native. We're going to opt-in. And so it actually happens at the navigation layer. So we can say, if a person transitions to the /user/signin route, instead of just rendering that WebView right in place, push a native Swift or Kotlin. Depending on the context that we're in or the platform that we're in, push the native view onto the stack and use that. And so we're able to, on a screen-by-screen basis, make a decision of no, we'd like to opt into native behavior here. And so, if we did eventually see that the vast majority of the users of the platform are using it via the native app, we should probably continue to invest in that and push in that direction. I think we could do it in sort of a gradual style, and that is critically important to me. I don't want to make a big bet and then be like, oh no, we got to rewrite from the ground up. And there's no way to do that incrementally. It's going to be a whiz-bang Friday launch that everyone's going to hate. That's the thing I want to avoid most in the world. And so I think what we found now is this seems great for right now because it allows us to avoid this complexity explosion of three different platforms and trying to keep them in sync and trying to keep them up to date. But it does, I think, give us an opportunity as we move forward to slowly sort of transition things over. We are, to state it, this isn't just like wrapping a WebView around things. We are building essentially a mini framework on both iOS and Android, or roughly Swift and Kotlin is what the actual languages are, to work with Inertia because inertia is the core technology that we're using. Inertia, thankfully, has a nice little event system in there, so we can say, Inertia on navigate. And when a navigate event happens, we can hook into that and then connect it to whatever Swift or Kotlin runtime that we're building here. And there are a couple of different events that we can opt into. And so that's giving us the hooks that we need in the current architecture. But longer-term, if we needed to, we could just, I think, slowly transition everything over to be truly native mobile, and then that would probably be backed by more traditional API endpoints and that sort of thing. I want to avoid that. That's my dream is to stay in this happy place where we're always going to need some web presence. And I would hate for those to be fractured distinct things. I've worked with enough mobile apps that are wonderful native experiences, and yet I'm like, could you just give me the desktop view? Just scaled to...like, I'll even pinch and zoom because you're hiding data from me, and that makes me very, very sad. Please give me the buttons, and the text, and the content that you would give me on the web. And the fact that you're not is just breaking my heart right now. And, frankly, for our user base, consistency of experience is something that I think is really important. So that's another facet of the conversation that is really interesting to me of like; I don't want it to be different on each platform. Certainly, a three-column layout doesn't work on an iOS app that is zoomed in 150%. But we can turn that into each column is just floated down and then otherwise have all the content in there. And I believe in that as sort of a fundamental truth of let's reshape the content but not fundamentally rethink it. I say that as something that I believed deeply. But as I said it out loud, I was like, yeah, but also, I don't know, make it work on the platform it's on. So I can see both sides. But I have had enough experiences personally where I'm sad about the app that I'm using. STEPH: Yeah, I could also see an argument for both ways where you don't want it to be fundamentally different, but then also, you want it to fit the platform. And then there may be some advantages to the fact that there is a different platform, and you want to utilize that. I also agree with the not hiding of the data. I have felt that pain where I have an app, but I really want to go to my desktop, and I really want to use it there. But then on mobile, it's then hiding, and I realize it's hiding. And that inconsistency really frustrates the heck out of me. So I can understand that as well. Overall, I really like this. You're taking a bet in a direction of we should have a mobile presence, and we should start attracting people through this new marketplace. But we want to reuse a lot of the logic that we already have before we go so far as then we're going to have to start building for each different platform. Because while I don't have a lot of experience in that area, the times that I have been part of teams that are building native apps, it's a big investment. I mean, they hire people very focused on that; designers have to design for browser, for mobile, and then for native, and then everything has to stay in sync across. You have to think about how a feature is going to work across all three of those different views. And so it is certainly not something to go into lightly, which I think is exactly what you're describing is that you're looking for that in-between to how can we start working our way in this direction but yet also do it in a way that we're reusing a lot of the work that we have versus having to invest full sail into then building out these different platforms? So I'm going to go with this is not a terrible idea. [chuckles] I'm excited to see how it feels once I can download this and check it out. I'm excited to then see how that feels from a UX perspective. But overall, everything you're saying really jives with me. It makes a lot of sense. I am curious, what about React Native? Is that something that you considered using? CHRIS: Oh yeah, great question and definitely something that we considered. We're not using React on the backend, so that was actually a consideration when I was thinking about Svelte initially is I assumed we'd be building a React Native app eventually for the native platforms. But I talked myself into Svelte for the web, and that is not the reason that we're not using React Native for the native apps. But it is an interesting sort of constellation of technologies that we have now. We're not using React Native because I'm clinging to this idea of what if we could have a singular experience? So React Native fundamentally you're building a native app that this is this bundle that you download that's got all of the UI and that front-end logic in that bundle that you download. And then when it wakes up, it makes some calls back to some APIs to get some data or to decide if I can do an action or to actually do an action, all those sorts of things. But you're building out a Rest or GraphQL or one of those APIs. And with my explorations of Inertia, I found that what if I didn't need to do that? What if I could do a more traditional Rails CRUD-like experience but CRUD in a good way (I mean it in the very positive sense of the familiar architecture) and still give users a delightful experience but not have to build a distinct API where all of the or majority of the logic was on our client-side? So if I did that, then my web client would need to be that much smarter. And each of the iOS and Android clients would need to be that much smarter because that's fundamentally how these technologies work. UI components they can give a higher fidelity experience, more native-like experience, but they tend to own a lot more of the smarts. And one of my core beliefs is however long I can get away with this, I want to keep as much intelligence on the server as possible and have my view layer be as minimal and as simple as possible. So I think React Native is a really fantastic technology for that sort of work. But my goal was to avoid that sort of work entirely. What if we had a singular way that we had the logic exist on the server-side, and then we rendered pretty minimal view layers? Or, from a user experience, the view should do all this stuff and show all of the things that they want. But I want that view layer to be as naive as possible. And by naive, I mean in the positive sense of like, I want to be able to change this very rapidly. I want to be able to evolve it and iterate it. And so this is more of a buy into I think the thing that Inertia gave me is valuable enough and if I can keep using that and reuse it, especially on these mobile platforms...now if we add a new fundamental part of our Sagewell platform, if we have that, it just exists on each of the iOS, the Android, and the web, and that's fantastic. And we're going to keep a really close eye on what experience that gives to the user. And is it still great? But presuming it is, the complexity savings there are so huge. Our team is a team of web developers that is able to think about things holistically and singularly. We implement it once within our stack, and it just works. And if we can do that, that is worth a ton. We may not be able to do that forever. But for now, especially while we're figuring things out, while we're super early on as a company, I think that savings and complexity is worth a lot. So it'll be interesting to see how it plays out, and will certainly report back. But I'm a big believer in this little adventure we're on. STEPH: Yeah, you said it perfectly there at the end; you're a team of web developers. And so as long as you can stick to that, then that's what's best for y'all and the team and the product. So that's wonderful. I have a short segue because I had a little bit of inspiration when we were talking about terrible ideas. I want to circle back to your other terrible idea because I have a terrible idea for your terrible idea about strings and symbols. Okay, so my terrible idea is you're talking about using HashWithIndifferentAccess for everything. What if you had a class or method that then will first try to access via string and if that fails, access via symbol, and then if that fails, then it fails loudly? So you now have this let's try this, and then let's try the next thing. I have strong feelings about this as I'm saying it. CHRIS: [laughs] STEPH: But we're in the terrible idea segment, so I'm going to embrace it. This is my terrible idea. CHRIS: HashWithIndifferentAccess with runtime exceptions. I think HashWithIndifferentAccess under the hood probably does what you're describing of, like checks one and then checks the other or checks has_key is probably the underlying implementation. I haven't actually looked at it. But some version of that makes sense. Falling back to the key error gets interesting. I did see a different thing recently of a deep fetch, which is something that I want, to stop trying to make fetch happen, except I'm going to try and make fetch happen. We thought about this a bunch where we have these objects that we need to traverse into. So we use dig to get into the third layer of the object, but dig doesn't care. And it's just going to happily nil out whatever. So I'm like, no, dig but then right at the end, fetch, deep fetch. I saw somebody post this recently. So deep fetch is something I want to make happen. HashWithIndifferentAccess, which raises at the end also intriguing. STEPH: So yes, but this will be a little different because this one, you don't have to do the transformation process upfront with HashWithIndifferentAccess where you have to pass the data first, and then it transforms it so then it can do these two different lookups or the fallback. This one, you're skipping the transformation process, and you're using your own custom method that then does that first check for a string or first check for a symbol and then default back to the other one and then fail loudly, yeah, if both of those fail. CHRIS: Interesting, and I have to see what it looks like in practice. But I mean, broadly, I'm into something in this space. Let us find some simplicity. That is what I want. STEPH: Let's find some terribleness and see which one feels not so terrible. [laughs] CHRIS: Some terrible simplicity. Well, I like that idea. We'll see where we get to with it. But I think on that note, and we've said a bunch of stuff today, should we wrap up? STEPH: Let's wrap up. CHRIS: The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeee!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

The Bike Shed
327: Estimate Crafting

The Bike Shed

Play Episode Listen Later Feb 22, 2022 42:33


Steph joins Chris in trying new things! For her, it's a new email client – the Newton email client – because she really wants to love her inbox. She also talks about implementing a suggestion from Chris on improving CI speed. Chris continues his search for the perfect to-do list app. (It's not going great.) But he has made hiring progress and is excited to move on to the next step: onboarding. Together they answer a listener question who asked for advice on crafting project estimates for clients. This episode is brought to you by ScoutAPM (https://scoutapm.com/bikeshed). Give Scout a try for free today and Scout will donate $5 to the open source project of your choice when you deploy. Services down? New Relic (https://newrelic.com/bikeshed) offers full stack visibility with 16 different monitoring products in a single platform. Newton (https://newtonhq.com/) Subscribe to Email Newsletters in Feedbin (https://feedbin.com/blog/2016/02/03/subscribe-to-email-newsletters-in-feedbin/) GitHub - Shopify/packwerk (https://github.com/Shopify/packwerk) Sunsama (https://sunsama.com/) TickTick: To-do List, Tasks, Calendar, Reminder (https://ticktick.com/) Become a Sponsor (https://thoughtbot.com/sponsorship) of The Bike Shed! Transcript: CHRIS: I am now recording. STEPH: Me too. CHRIS: [laughs] That's my recording voice. STEPH: [laughs] CHRIS: That's how you can tell. STEPH: I just like how it sounds suspicious where we're like; I'm now recording, so be careful. [laughs] CHRIS: This is now on the record. Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Chris Toomey. STEPH: And I'm Steph Viccari. CHRIS: And together, we're here to share a bit of what we've learned along the way. So, Steph, what's new in your world? STEPH: Hello. Happy, happy Friday. Oh, I have something that I'm excited or intrigued about. I don't know. Okay, I'm hyping it up. [laughs] But I'm realizing I'm also very skeptical of it. CHRIS: This is the best sales pitch I've ever heard. I'm so excited to hear what this is. [laughs] STEPH: I am trying a new email client; it is the Newton email client. And I so want to love my inbox. I want to check on it. I want to help it grow. Okay, that's the opposite. I want to help get through all the emails that come through, but I just want to love it. I want it to be a good space that I want to go to. And I just hate email so much. And it always feels like this chore that it's really hard for me to bring myself to do, but yet it's really important because a lot of good things come through email. So this is my rambly way of saying I'm trying the Newton email client because I saw on Twitter from Andrew Mason, who has very similar feelings that I do about email, where we are just not fans of it. And we rarely check it and have declared email bankruptcy at several points in our life. And he's also one of the co-hosts for Remote Ruby. But I saw on Twitter that Andrew was talking about the Newton email client and how it actually made him feel that he enjoyed writing and looking through his inbox. And I was like, yeah, that's the sales pitch I need. So I'm giving it a go. It's been only a couple of days. But one of the nice things I have noticed about it is it's very focused, and there's not much noise, and it actually feels like very minimal design where if you open up like a new email, so you're opening up a new draft, there's no much noise. You get to just focus, almost like you're writing a little blog post or journal post or something. It takes away a lot of the noise. While in Gmail, it's going to open up a small window in the right, but then you still have the rest of the noise that feels distracting. So I like that very intentional like, hey, you're just doing one thing, just focus on this. And then also you can integrate other email accounts as well. So you can have one-stop shopping versus Gmail, then you have to click around and sign in, sign out, or visit different email accounts. So we'll see if it helps improve my email life, but that's something new I'm trying. CHRIS: Very interesting. So you're fully on inbox zero life now. That's what I'm hearing. [laughs] STEPH: Ah, hmm. I don't want to lie to you. [laughs] We have a good friendship. I won't start lying now. CHRIS: I appreciate that. So you're halfway to inbox zero. You're not even entertaining that idea, right? This is just you want a better tool to do email. STEPH: Exactly. Inbox zero is not incredibly important to me. But I do want to make sure that I know that I've seen everything important, and I know where to find things. And then making sure that I am responding to people in a timely manner. Those are more my goals. Inbox zero, if that supports it, then great, I'll work on it. But not necessarily that has to be the goal that I reach. CHRIS: Gotcha. I'm not seeing Newton, but I'm intrigued. Particularly on mobile, I have the Gmail mobile app, and that has unified inbox, which I appreciate. But Gmail on the web does not, and I find that odd. And I've never found a mail app that I enjoy because I want some of the features of Gmail. I want to do Gmail snoozing because I still want that to be consistent and whatnot. And to be honest, that's the main way that I get to inbox zero. I just say future me will have more time. I actually tweeted recently. It was a screenshot from my Saturday inbox, which I think was 15 emails that I'd snoozed from the previous week into Saturday morning. Because I'm like, Saturday morning me will have so much time, and energy, and coffee, and it'll be great. And then it became Saturday morning and, ooph, what a view. STEPH: [laughs] Yeah, your snoozing tip has been life-changing for me because that's not something that I was using all that much. The two things are, one, schedule send so that way if I do have a sudden burst of energy and I want to write an email, but I want to make sure that person doesn't get notified until a decent time. Being able to schedule an email and snoozing is amazing. I think Newton and Gmail have pretty much similar features. I was trying to do a comparison. I was like, is there something really snazzy that Newton does that Gmail doesn't already give me? But it looks like they all do about the same, having those important features like snoozing and then also being able to schedule emails. So I think it really just comes down to a lot of the UI, and there may be some other stuff I'm missing since I'm new to it. But that's the main appeal for me right now is the focus and the look and feel of it. So then maybe I will find looking through my inbox a more zenful experience, I think is how I saw them advertise it. CHRIS: Well, I definitely look forward to hearing more as you explore this space. I will say looping back to what you were just commenting on around deferred send, which is definitely something that I use, but you described one of the reasons that I use it. So the idea of wanting to be respectful of someone else and not send them an email on Sunday night because you happen to be working at that point. But you don't want to put that on their plate. I would say equal amounts; that's the reason I use scheduled send. And then the other reason that I use scheduled send is please, for the love of God, I do not want another email back in my inbox. So I will reply to something such that now I'm done with that, but I will schedule send it for the next morning. Because tomorrow morning me can deal with whatever reply this generates. There's some adage; I don't know if it's an adage, but the idea that every email that you send generates 1.1 emails in reply. So emails just have this weird way of multiplying. And so if you send one out there, you're probably going to get something back. And so often, if I'm trying to clear my inbox, I don't want to get another email in my inbox at that moment. So I will not actually send the reply. I will schedule it for a future time because I do not want to hear. I want no new inputs at this point. I'm trying to process them. So that's part of why I use deferred send. STEPH: I had not thought of that, that yeah, that if you schedule it for tomorrow, you've really gamified this inbox zero because you're like, yeah, if you send something, then you might get an email back. But you're like, if I wait till tomorrow to send it, then I'm less likely to have another email, and then I've hit inbox zero, and I'm set for the day. I like it. It seems helpful. CHRIS: Yeah, inbox zero sounds like an altruistic thing, but it is not. It's a way to force myself to have to make decisions, which is something that I want to get better at broadly. And that's part of the role that I have now. A lot of what I'm interested in exploring is just getting better at making decisions, being more decisive, being more action-oriented. Because I just have a tendency to make many, many spreadsheets and think about stuff for a while and take a long time to make a decision. But I don't get to do that, particularly now. But broadly in life, that's probably not the right mode to be in. So inbox zero is another thing that forces me to deal with things rather than just be like, I don't know, I don't know, I don't know, and keep looking at the same thing over and over. So just more thoughts about inbox zero, but now I'll stop talking about it. STEPH: I do like that, though. And you're totally right; it can be a very helpful constraint. And I think that's sometimes why I fight it because then I haven't curated my inbox enough that then when I go to it, there are so many interesting things that then I feel a little bit overwhelmed where I'm like, oh well, I want to read this, and I will look at that. And this seems interesting, and maybe I should be a part of this. It feels like one of those like; you could be a part of these ten amazing things. Do you want to be a part of all of them? And given a person that it's hard for me to say no to or recognize that no, I'm just going to not do anything with this, that is hard for me and would be a good skill for me to hone in on and practice and make quick decisions and be very realistic. Because I used to be subscribed to more newsletters, and then I finally had to stop subscribing to them because it had that same effect on me of that FOMO of like, I'm missing out on this great article or this great video. And I've become more honest with the fact that my Saturday morning self isn't going to want to read through a bunch of newsletters and videos about coding, that I'm going to want less screen time. So that is a really good constraint and helpful skill to cultivate for sure. CHRIS: All right, I said it was done, but one more thing. I feel like I've mentioned this in the past, but Feedbin is the thing that I use for RSS. I still believe in RSS as a technology. But everyone's moved to newsletters these days that go via email. Feedbin gives you an email address that you can use to subscribe to newsletters, and then they do the job of converting that into an RSS feed. So for me, I take something that was now a push into my inbox, and now I can pull whatever I want from that RSS feed. And on Saturday morning, if I'm feeling like, with a cup of coffee, I can enjoy some newsletter about all the new hot tips in Svelte land or whatever it is or not. But it's not clogging up my inbox. And with that, I think I'm actually done talking about inbox zero. [laughter] STEPH: Yeah, that's a nice separation. We could keep going. I have full faith in us that we could keep going about this. But I'll share a slightly different update. I've been implementing a suggestion that you provided a couple of weeks back where we were talking about Rspec's selective test running and how some applications will speed up their test. If you change one part of the codebase, then perhaps you only need to test this chunk of test. You don't actually need to run the full test suite. And that is complicated and seems hard to get right, and really requires understanding boundaries. But then also knowing Ruby, then how do you really identify? Do you really know where this method is being called and can identify all the tests that need to be run? I think we'd mentioned before there's a really good article from Shopify where they have worked on this and created an open-source project called Packwerk. So we can link to that article in the show notes. But more specifically, you suggested, well, what if you just change a test file? That seems very low stakes and also has the benefit of creating a reward where if someone does see something that they can improve in a test, then that's a very quick feedback. Let me just get this change. It's going to be fast on CI. I can merge it right away and also saves time on CI. So I've been working on implementing that change. And it's one of those the actual change is easy, like checking with Git to say, "Hey, what files have changed?" Does it have an _spec.rb at the end of it? Great. Does it not? Okay, we've changed some application files. So let's run the full test suite. That part's easy. Getting it integrated into the build system has been more complicated just because this team has done a lot of work around trying to improve and speed up their test. And there's a fair amount of complexity that's there. So then figuring out a way to stitch my change into all the different build processes that take place has proven to be more difficult. But it's also been insightful just because it has now helped me really understand and forced me to learn, okay, what are all the different steps? What's important for each one? Where can I cut off the rest of the running of the test and instead just focus on running these tests? So in some ways, it's been challenging, but then on the positive side, it's been like, okay, well, this has taught me a lot about the existing system. So at this moment, it is still a work in progress. I'll have more updates in the future. I am excited to see the rewards. I've gotten to the point where I just have a proof of concept where I've gotten pushed up, but it's not production-ready. But it's at least I just wanted the feedback that I'm in the right spot and that we're running just the right test. And so far, it does seem like it's going to be a nice win, even if it's maybe not used by everybody because it's probably rare that someone is altering just a spec file. But for people who are looking specifically to improve the CI build time and working on tests, it will be very helpful to them. So yeah, I'm sure I'll have some more updates in the future. What's going on in your world? CHRIS: Well, I definitely look forward to hearing more about that. However, we can improve CI speed; I'm super interested in that as a topic. Mid-Roll Ad Hey, friends, let's take a quick break to hear from today's sponsor, New Relic. All right, so you've probably experienced this before where you're just starting to fall asleep, and it's a calm, code-free peaceful sleep, and then you're jolted awake by an emergency page. It's your night on call, and something is wrong. But I have some good news because you have New Relic, which means you can quickly run down the incident checklist and find that problem. So let's see, our real user monitoring metrics look good. And that's where New Relic measures the speed and performance of your end-users as they navigate the site. But it looks like there's an error in application performance monitoring. If we click on the error, we can find the deployment marker where it all began, roll back the change, and, ooh, problem is solved. We can go back to bed, back to sleep, and back to happy. That's the power of combining 16 different monitoring products into one platform. You can pinpoint issues down to the line of code so you know exactly why the problem happened and can resolve it quickly. That's why more than 14,000 other companies, including GitHub and Epic Games, use New Relic to improve their software. So you know that next late-night call is just waiting to happen, so get New Relic before it does. And you can get access to the whole New Relic platform and 100 gigabytes of data free forever. No credit card required. Sign up at newrelic.com/bikeshed. That's newrelic N-E-W-R-E-L-I-C .com/bikeshed, newrelic.com/bikeshed. CHRIS: Well, similar to your email adventures, I continue on my search for the perfect to-do list. It's not going great, if we're being honest. [laughs] To be clear, because I've mentioned this on a few different episodes, I'm not spending much time on this at all, some but not much. And so it's not really moving. But there are two interesting things. I took a look at TickTick, which was one that I mentioned in the past, a tool for this. It seems good. It seems like an intersection between things, which is what I'm currently using, Todoist, which I've used in the past, and some other tools. So I think I'll probably explore that a little more. It seems like a good option. Decidedly, the most interesting thing is a tool called Sunsama, which is different in some interesting ways but very interesting. So one thing to note about it is it's $20 a month, which is a lot of money for one of these tools because most of them are like, "We're $20 forever, and then it's free." And it's a surprisingly low-cost space. And so, they're definitely positioning themselves as a more costly entry. I would be fine with paying $20 a month for a tool if it really is like, no, cool, I feel great. I'm more productive. I'm happier when I'm not working, et cetera. But what's interesting is they seem to do a let's reach out to all the places that tasks can live for you. So there's your inbox for email. There's your Trello board that you've got. There are GitHub issues. There's Slack. There are all these different sources of potential tasks. And they do a really good job of integrating with those other tools and then allowing you to pull that list into Sunsama and then make each day you have a list. And those items can be like, this is a reference to a Trello card on that board. This is a reference to a Slack conversation over there. So I'm super intrigued by it. It's also got a very intentional plan your day mode, which I like because that's one of the things that I'm really looking for is at the end of the day, I want to clean everything up, make sense of all of the open items, and then reprioritize and set up for the next morning so that I can just hit the ground running. That said, I tried it, and it just didn't quite click. And I think it's one of those it takes some effort to understand how to use it. So I'm not sure that I'm going to get there. But it is super interesting because that idea of our work lives in all of these different tools these days feels very true. And so, something that is trying to act as a hub between them to integrate them is very interesting to me. Again, I haven't really gotten anywhere on this. I'm kind of just reading blog posts, as it were. So I'll report back if that changes, but -- STEPH: The search continues for the right to-do app. Yeah, that seems interesting. I don't know why I'm feeling hesitant towards it. I'm one of those individuals...you're right; there are so many tools. And the fact that they integrate with a lot of them seems really nice. I'm at the point where I just grab links to stuff, and I'm like, hey, if this is my priority, I grab a link to a Trello ticket, and then I just copy that into my to-do. I guess I like that bit of work over having to integrate with a bunch of different platforms. Because once you get used to integrating...I don't know; I'm just rambling. But I wish you the best on this journey. I'm excited to hear more. [laughter] CHRIS: Thank you. I will certainly report back. But yeah, nothing pointed to share at this point. But I do have something pointed to share on the hiring front, which is that we have hired some folks. STEPH: Hooray! CHRIS: Yay. So this has been a fun saga across a couple of different episodes. And in my mind, it feels like this much longer, more drawn out thing, but it's; actually, I think, come together relatively quickly, all things considering. We've got someone who's starting in a little over a week's time, and then someone else who's starting in, I think, two or three weeks after that. So that'll be great. Hopefully, we can transition into onboarding, which is a different whole approach. But hiring as a distinct activity can scale back significantly. As we discussed last week, I want to be in the always be hiring mindset but in the more passive mode of having conversations with folks, staying connected. And if a great candidate comes along and it's the right time, then bring them on the team but not actually actively reaching out and all that sort of stuff, which will be great. Because it turns out that takes a lot of time and also a lot of energy for me. Having those first conversations, going into it very intentionally trying to communicate about something, and there's a tone of salesmanship to it that is not my natural resting state. So I come away from each conversation being like, that was fun, but also, I'm drained now. Why am I so drained? So not having that be a thing that is filling up my calendar is great. And also super excited with the folks that'll be joining the team and to be able to now grow our little team and define the culture and the shape of the groups that we will be collectively. I'm excited for that work and what we can build together. So yeah, it's an exciting time. STEPH: That's awesome. Congratulations. Because yeah, everything you're saying sounds like it's just been a lot of work. So that's very exciting. There's someone that I was chatting with earlier today where they were talking about the value and the importance of understanding what your natural skills are and the things that bring you energy. And so you're mentioning there are certain activities that you enjoy them, but they're also draining because perhaps they are on the outer boundary of what you might define as your own natural skill or the things that get you really excited. And I found that all very interesting. It had me thinking about that today about where are the natural areas that I find that I get energy that are easier for me? And then making sure that I'm trying to prioritize my day so that I am more focused on the activities that just align with who I am and also that I'm engaged with and then also looking for ways to stretch. But they made the point that if you are always in a space where you are not using your natural talents, and you're always having to stretch, then that can be what leads to burnout. Versus if you're in that sweet spot, that zone of where you are using your natural skills, but then also stretching a bit. And I think there are some assessments and things like that that will help you then determine what are my natural skills, and what do I like to do with my time? I just like that style of thinking and recognizing, like you said, like, hey, I did a thing. It was fun, but I'm drained. So now I know that this is something that requires more effort for me. Like hiring, that's one for me. I really like interviewing. I like talking with people, but I'm so nervous for them because I know interviews suck. [laughs] I just have so much empathy for them where I'm like, this is going to be a hard day. We're going to make it as pleasant and positive as possible, but I know this is a hard day. And so I feel like I'm in it with them. And so afterwards, I feel that same relief of like whoo, okay, interview day is over. CHRIS: I don't know that I quite achieve the same level that you do but in no way am I surprised that that is your experience of hiring. And just to name it, you're a wonderful human being that feels for the people on the other side of the hiring table. Like, oh my God, this must be so stressful for you. It's so kind of you to be in that space with folks. But coming back to what you were saying a moment ago, that idea of, like, understanding where your strengths are and where they're areas that you're not quite as strong. And I think critically, the question of like which are the ones where I want to just kind of say no to? I'm like, that's fine. This is not going to be a competency of mine. And I'm going to just avoid that or find other people to work with that balance that out. So for me, sales is the thing that I don't think that's ever going to be my bag. I don't think I'm ever going to move in that direction, and that's totally fine. Whereas decisiveness, which I was describing, is like, I think that's the thing I could get better at. That is one that I don't want to sleep on that. I don't want to say, "That'll be fine. I'll just have other people make the decision." No, I need to get better at making decisions, making decisions with less information or more rapidly, having a bias towards action. All those things I think will be deeply beneficial. So I'm trying to really lean into that. Whereas yeah, again, the sales stuff I'm like, yeah, and there's plenty of examples of this otherwise. But I've also been coding a bit more this week, which has been lovely because the hiring stuff has ramped down. And that has freed me up amongst some other stuff that's been going on. And you know, I like to code, it turns out. It's fun. I just clack about on my cherry brown keys, and it's great. STEPH: Do you remember when we first got introduced to mechanical keyboards, and we had co-ownership of one of the keyboards? And we literally had days of where it was like your turn to use the keyboard. And then it was my turn to use the keyboard. How long did we keep that up before we were finally like, we should just buy our own keyboards? CHRIS: It was a while because we were working with a colleague who was trying out a Kinesis, I want to say, one of the split little bowl of keys. But yeah, we had a shared custody over a keyboard, and it was fantastic. I remember that very fondly. STEPH: The days that it was my keyboard, I would go to the office and be like, oh, today is my day at the keyboard. This is great. This is going to be such a wonderful day. [laughs] And now I'm just spoiled. CHRIS: It went on for a while, though. And this was something where we both obviously enjoy this keyboard. Why don't we just buy one of these keyboards? We totally could have done that. And yet, for some reason, both of us were like, no, but what if...I got to think about this. Again, decisiveness. [laughs] We come back to this topic of well; I had to really think about it. And then somebody got the 92-Key test or whatever it was in the office. And so I just went over and poked every one of those for a while. STEPH: Exactly. It was option overload where we're like, well, okay, we're going to buy one, and then you open it up and search, and you're like, oh, you want options? We have options. Do you know about the blues, and the browns, and the colors, and these different options? Like, I don't know any of this language that you're talking about. I just want to clackety-clack. So yeah, it took time. We had to do our research. CHRIS: And then I ended up on basic browns. So here we are. Let's see, popping back up the stack a couple of levels, hiring that went on for a while. Now it is less going on. Although to be clear, like I said, always be hiring. So if anyone out there in the world is hearing what I'm talking about with Sagewell or seeing any of the stuff that I'm putting on Twitter, which isn't much, I occasionally just post screenshots of my commit messages, which recently included better snakes as a commit message. [laughs] I have to dig into that or not. But we were just doing some snake case to camel case conversion. But the commit message was better snake, so here we are. Anyway, if any of that sounds interesting, please do reach out. But I'm excited to transition back to focusing more on the work. On that note, actually, I'm going to call it interesting things that is happening right now organizationally is; we are working with an external security firm to help with some...they helped us out with a penetration test when we needed that. And then they have stayed on retainer and are helping with various different configurations, taking our AWS S3 buckets and making sure those are nice and secure, and all that kind of stuff. But we've recently started to focus more on organizational security, specifically a bowl of acronyms. We've got SSO for single sign-on, MDM for something device management. I don't know what that first M is. I probably should learn it, but it's fine. That's why I've got help on this is I think they know what the acronym stands for. But so we're working on each of those. And on the one hand, they're probably going to be kind of annoying, like having to go through the single sign-on. It's a whole thing, and it's harder to sign into stuff sometimes. I mean, ideally, it's actually easier. But in my experience, it adds some friction at some points. And then MDM means that there's now some profile manager on the computer. So I can say like, "Every computer must have full disk encryption or else you can't use it. And we need a passcode, and it must be this long and those sorts of things." So it's organizational controls that I think are good for us having a robust security setup throughout the organization. But yeah, they're the sort of things that I think historically, I probably would have, as someone working in an organization, had been like, do we have to? Do we need these things? Couldn't I just do whatever? But now there's something about it that I really like. I'm trying to name it in my head, but I'm kind of like, I don't know. This feels like growing up as an organization. And there's always weird corollary that I've been thinking about with the Rails app that we've been building, intimately familiar with just everything that's going into it. And I know the vast majority of lines of code. I haven't written them all, but I've had an eye on all of the different features that we're building in. And it's hard to get out of that headspace where it feels like a bunch of pieces. It doesn't feel like a hole to me, even though it definitely is. But when does a bunch of boards that you nail together become a boat? To make a really weird analogy because that's what I do; it's a hobby of mine. But when does that transition happen? At some point, certainly. But that's harder for me to see on the code side. And organizationally, somehow getting these things in place feels like the organization sort of an inflection point for us, a growth point, which is I'm really excited about it. Even though they're probably going to mean a ton of annoying nuisance work for me because I'm the person in charge of making sure it all gets rolled out. And anytime anyone locks themselves out of an account, I have to help with that. And so it's probably just putting a bunch of annoying work on my plate. And yet, I don't know; I'm kind of excited about it. STEPH: I feel like that shows our roots in terms of how we approach projects that we work on where you mentioned do we need this? Do we need this yet? Because I feel that we're constantly as developers and consultants just we're trying to advise on the more simplified do we need this? Is this the right thing to spend the money on? How do we know? What are the metrics? What does success look like? And all those questions. So I feel like the way you just phrased all of that just really shows that sort of mentality that you grew up with in terms of checking in, and yeah, it's cool. Like you said, you're at a growth point where then it's like, yes, we are at this point that I've asked myself all those questions, and we're here. This feels like the right next step. CHRIS: I like the way you described it as that you grew up with, my formative growing years at thoughtbot. Mid-roll Ad Scout APM is an application performance monitoring tool that's designed to help developers find and fix performance issues quickly. With an intuitive interface, Scout will tie bottlenecks to source code, so you can quickly pinpoint and resolve performance abnormalities like N+1 queries, slow database queries, and memory bloat. Scout also recently implemented external service monitoring, adding even more granularity when it comes to HTTP requests and API calls. So give Scout a try today with a free 14-day trial and experience first-hand why developers worldwide call Scout their best friend. And as an added bonus for Bike Shed listeners, Scout will donate $5 to the open-source project of your choice when you deploy. To learn more, visit scoutapm.com/bikeshed. That's scoutapm.com/bikeshed. STEPH: Well, switching gears just a bit, we have a listener question for today, and this one comes from Stephanie. So not me, another Stephanie in the world. Hello, other Stephanie out there in the world. And they wrote in, "Hi, Steph and Chris, fellow software consultant here. And I'm wondering if you'd consider talking about how to craft a project estimate for a client on the pod. It's such an important aspect of consulting." Amen. I added the amen. "And I feel like I'm very much impacted as a project team member when the estimate isn't accurate." Double amen. So true. [laughs] "Would appreciate any and all thoughts, especially since it might be part of my job in the future. Thanks." I just realized I put us in consultant church by adding all those amens, but here we are. [laughs] CHRIS: I'm glad you clarified that they were additions by you and not part of the original question coming in. STEPH: Sure. I don't want to speak on behalf of Stephanie. So I have some thoughts on the matter. I think there are a couple of different ways that we can talk about this particular question because I think there are different formats as to when you're estimating and who you're providing the estimate for. But I'm going to pause because I'd love to see what you think. How do you go about approaching crafting an estimate? CHRIS: Sure. I'm happy to share some thoughts. And for a bit of context, this question came in to us, frankly, many months ago, but I did send an initial reply to Stephanie because I know that sometimes we take a little bit of time to get back to folks. So if ever you do send in a question, know that one of us will probably respond via email earlier, and then eventually, will make it on the show. And again, just to say, we do so appreciate when folks send in these questions. It's an interesting way to shape the conversation and a way to get topics that you're more interested in into the fold here. But so the two main ideas that I shared in my initial reply were, first, is an estimate really necessary? I think that's a critical question because an estimate implies that this thing is knowable. And as many of us, probably all of us, have found out at some point in our lives as software developers, it's really hard to do software estimation, like wildly difficult. And not just the thing that we'll eventually get better at it, which you do, but there's just some chaos. There's some noise in this work that we do that makes it so, so difficult to get it right. So pretty much always, I will ask, like, do we need to estimate here? What if, instead, we were to flip the whole question on its head and say, let's set a deadline. Let's say two months from now that's our deadline. And let's ruthlessly reprioritize every single week to make sure that we're building something that's meaningful, and we're getting there. And obviously, we have to have some general idea of what we're doing. Is two months a meaningful amount of time to build a rocket to go to Mars? Probably not. But is it enough time to build an app that can allow users to sign in and manage a simple list of items? Yeah, we can definitely do that, and we can probably add a bunch of more features. The other thing that I think is worth highlighting is there's a bunch of stuff that is table stakes and very easy to do. But I would, whenever doing estimation, emphasize unknowns. So, where are the external integrations with other systems? Where are the dependencies that rely on other folks to provide some inputs into this process that we can't be certain where there'll be? In my experience, the places where estimates go awry are often these little intersection points that you're like, well, this will probably take a day, maybe two. And it turns out; actually, this can somehow balloon into a month. That's not a thing that feels comfortable saying in an estimation process, but it is definitely real. I've seen it happen so many times. And so it's those unknowns. It's those little bits that I would emphasize as part of the process if you do need to do an estimate and say, all right, here's the boring stuff. I think we can do that pretty easily. But this part, I don't know, it could be a week, could be three months. And frame it in that way that there is this ambiguity there. Because if someone's asking you for an estimate and they're looking for like it is seven days and two hours exactly, it's like, well, that's not realistic. That's not how this thing works. Unfortunately, I wish it did. But pushing back and changing the conversation is the thing that I have found valuable. I think there's some other really interesting stuff in here around the team dynamics that Stephanie is talking about. But I want to send this over to other Stephanie to see your thoughts because I'm super interested to hear what you have to say as well. STEPH: Oh, I like how you hinted at the team dynamics. Yeah, that could be a fun one to circle back to. So I love how you called out highlighting the unknowns. There are a couple of ways that this comes to mind for me. So there's the idea of the weekly or the bi-weekly estimates that we make as developers and designers. So let's say we as a team are getting together to focus on a chunk of work and decide what we can and can't get through. And that feels one of those the more you get to practice it more frequently; you get to ask a bunch of questions. And that feels like a good rehearsal and exercise of how to go through estimates. And I know you and I have pretty similar strong feelings around how those estimates are then treated by the company. They should really just be used for the team to talk through the complexities in the work to be done versus used to communicate outwardly as to this is when it's definitely going to ship. So there's that more immediate practice of providing estimates. And then there's the idea for more of a consultancy or a company, and someone is coming to you, so thoughtbot being a great example of then how do we work with teams that are looking to come to us and gain an estimate for getting a certain feature implemented? So actually, I went to the source on this one. I went to Josh Clayton, who does a lot of the conversations for the Boost team when it comes to talking with clients and about the potential work that they would like to be done. And mostly our work is often teams will hire us. They have specific goals in mind, but they're really looking to hire ongoing development and services. So they really want to add to their existing staff. And then it's going to be an ongoing relationship versus a hey, we need you to quote us for how long it's going to take to implement this particular feature. And on that note, we don't do fixed-bid work. So we don't say it's X dollars for specific features. But on the realistic side, customers are often capped by a budget. And so that estimate is very important to them because it could be a difference between it's a go versus a no go. So if you have larger companies that are like, "Yep, we want to engage with thoughtbot. We really just want additional development power and design services," that's great. For those that are smaller, it could be an individual product owner, and they need to say, "I really want this feature, but I only have this much money. And frankly, if I can't ship it by this time, I'm not going to do it because it's not worth the investment to my company." And then, in those cases, those are the ones that we're going to spend more time with them to talk about what does the fallback plan look like? And what's our opportunity for simplifying the features? And Josh, in particular, referenced this as systems thinking. So he will go through the idea of drawing out the set of steps, understanding the complexity of the different screens. So what are the validations? What are the external dependencies? What is owned by us and what isn't? What is the likelihood that we're going to get permission to simplify or remove complexity? And even then, when we start to provide some estimates, it's going to be in weeks. It's not in hours; it's not in days. It's going to be in a slightly larger time frame. And then we're also going to spend more time in the discovery phase to say, okay, well, we know you need to fix this particular issue, or you need to integrate with this particular service. So we're going to need to ask a lot more questions about your codebase. What problems have you already run into? Have you tried to do this before? Do we have experience doing this? Is this something that we can lean on and ask someone in the team? And, say, how long do you think it would take for us to work on this? And that's knowledge that isn't privy to everybody. It depends on where you're at in your career as to like, oh yeah, I've done this like five times before, and I know exactly how this stuff can fall apart. I know where the complexity lies. So I think that's why estimation is so difficult is just because it does often pull from that existing experience. And so, if you don't have that experience for a particular set of work, of course, it's going to be hard to estimate because you just don't know. So that was a very broad scope of as day-to-day developer and designers; I feel like we're constantly getting practice and estimating and communicating the progress of our work. And then on the larger scope of if you are a consultant who's then looking to give estimates to clients, then understanding what other need can you sell them? Just ongoing development services. Or, if they are a smaller team and very focused, then what legwork can you do ahead of time to de-risk the project? And then understand how much control you're going to have to be able to simplify as you learn more as you go. Because you're going to, you're going to uncover some things, and you're going to learn some things. And what's that collaboration going to look like? I do have one more concrete example I can provide around some of the smaller projects that we take on. So when we are helping someone that's, say, getting a new product out to market, then we do have a more deliberate three, four-phase approach where we first focus on discovery, and ideation, and validation. And then, we move on to iteration and then launching. And I really like how you said about providing a deadline because then that helps us scope aggressively as to what is the minimum thing that we can get out into the world that will be valuable? And then there's usually some post-launch support as well. But that's often how we will structure those smaller, more specific engagements. CHRIS: I think one of the critical things that you highlighted in there is that thoughtbot doesn't do fixed-bid work. So we're going to do these 20 features, and it's going to take four months. thoughtbot does not do that, and frankly, that's a privilege to be able to take that position and say, "No, no, no," we're not going to work that way. But it is, I think, a trade-off. It's not just something that thoughtbot does to be like, listen, that doesn't sound fun. So I'm not going to do that. It's a trade-off. Not doing that comes in concert with saying, "But weekly, we're going to talk about the work that we have done and the work that remains and constantly, ruthlessly, reprioritize and re-decide what we're doing." And it's that engagement, the idea that you can have a body of work, look at it and say, "Yeah, that'll take about six months," and then go away for six months, and then come back with the finished software. Our strong belief is that that's not the way good software gets built. But instead, it's a very engaged team where the product owner and the development team are in constant communication about each of the features that are being developed. And then again, ideally, on a weekly cadence, coming up for air and saying, "How are we doing? Are we moving in the right direction? Are we getting towards the goals? If not, do we need to simplify? Do we need to change things?" And similarly, as I mentioned deadlines, I feel like deadlines is probably a word that many people think of as very bad because deadlines often come with also a fixed scope, but that can't happen. That's two constraints, and you can't have them fighting that way. But a deadline can be super useful as a way to say we're going to put something out there in the future and say we're heading towards that moment. And let's, again, cut scope. Let's change what we're building, et cetera. But critically, not say, "We got a deadline and a fixed scope. We're going to do that." And so it's, again, just ways to gently shift the conversation around and say, what if we were to look at this from a different angle? Because just having a pile of work and saying, "That'll take six months," I've never seen that play out. STEPH: Yeah, to me, deadline is a bad word when the deadline is set by a team that's not doing the work. So if you have leadership or if you have someone else that is setting this deadline and then just passing that down to someone else to then fulfill, regardless of the feedback or how things are going, then yeah, then it can be a nasty thing, which I think is a little bit of in that question that you picked up on that you highlighted where there could be some interesting team dynamics that Stephanie called out, highlighting that I'm very much impacted as a project team member when the estimate isn't accurate. And I'm making some assumptions here because I don't actually know the exact situation that Stephanie is experiencing. But it sounds like someone else externally is setting these team estimates. And so then you're handed this deadline, and then stuff goes wrong, but you're still pressured to meet this deadline. And I've certainly been part of projects that are like that. And then that is one of the number one things that then often comes up in a retro or like, we don't have control over these deadlines, or we don't know why these deadlines are being set. And then people are working extra hours and working nights and weekends to then meet this arbitrary deadline that none of us signed up for, and that's just not fair to treat deadlines in that way. So full-heartedly agree that deadlines can be a very positive thing, but they need to be set by the people doing the work. And then there has to be discussions and updates about how is this going? Do we have control to simplify this? We thought we could do this with this particular external provider. It turns out that that's a nightmare. Is there another provider we can go with? Can we ship this incrementally? Like some features, you can't. They may have to go out wholesale. But is there a small chunk of this that we can deliver that is then a success that leadership and others can brag about? And then we can keep working on the rest of it. So it's always identifying what are the smallest wins, and how do we get there and getting buy-in from the team? Going back to something that you said earlier around, it is a privilege, where so as thoughtbot, we don't do fixed-bid work. And that is a nice thing for us to be able to focus on. But for people who do need to do fixed bid work and are relying on that, I think that often requires more legwork. And maybe that becomes part of your estimate. I'm just making up how I might approach this if I were trying to do fixed bid work. But there's a discovery phase that's very important. So maybe the first part of your estimate is I need to really understand the feature and see the different screens and know what materials we do or don't have. What does the codebase look like? Do I feel like this is a codebase that I can work quickly in? And is it going to be hindersome for me? But answering a lot of those questions to then help me paint a picture of, like, okay, this is a feature that I've implemented before, so I feel pretty confident that I could do this in a month. And then also communicating that this is my estimate but just know it's an estimate. And I will continue to update you each day as to how things are going or each week as to how things are going, and things may adjust. And we can always talk about ways about simplifying this. But I think that's how I would go about it is; frankly, it's going to require more legwork for me to feel more confident as to then telling someone as to how long I think the work will take. I think that's a nice, broad scope of the different types of estimate work to be done with the general idea of if you can avoid estimates and go for more frequent updates, then that's wonderful. But then, if you are forced into a corner where you need to provide an update, then just do as much research and honesty as possible and then still include the frequent updates. CHRIS: Yeah, that I think summarizes it quite well. STEPH: As a side note, it's been a lot of fun to feel like I'm referring to myself as a third person as Stephanie is working through this problem. So that's been novel. But yeah, thank you, Stephanie, for the great question. I hope that was helpful. On that note, Shall we wrap up? CHRIS: Let's wrap up. The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeeeee!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

The Bike Shed
326: Dongle Life

The Bike Shed

Play Episode Listen Later Feb 15, 2022 41:02


Chris is making hiring progress and loves asdf and M1 laptops. Steph is anticipating the arrival of one dongle to rule them all and talks about moving away from having a lot of Bluetooth connections. Two other big things on Steph's mind are education around factories because they're v important and shared examples and how they can be overused. She and Chris agree that it is better to tell stories in tests instead. This episode is brought to you by ScoutAPM (https://scoutapm.com/bikeshed). Give Scout a try for free today and Scout will donate $5 to the open source project of your choice when you deploy. Services down? New Relic (https://newrelic.com/bikeshed) offers full stack visibility with 16 different monitoring products in a single platform. GitHub - asdf-vm/asdf: Extendable version manager with support for Ruby, Node.js, Elixir, Erlang & more (https://github.com/asdf-vm/asdf) Factories Should be the Bare Minimum (https://thoughtbot.com/blog/factories-should-be-the-bare-minimum) Mystery Guest (https://thoughtbot.com/blog/mystery-guest) GitHub - varvet/pundit: Minimal authorization through OO design and pure Ruby classes (https://github.com/varvet/pundit) Become a Sponsor (https://thoughtbot.com/sponsorship) of The Bike Shed! Transcript: STEPH: Hello and welcome to another episode of The Bike Shed. [laughs] CHRIS: Hello, and I'm singing, and I love singing. STEPH: It's Buddy the Elf; what's your favorite color? [laughter] For reals, here we go. Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Steph Viccari. CHRIS: And I'm Chris Toomey. STEPH: And together, we're here to share a bit of what we've learned along the way. So hey, Chris. What's new in your world? CHRIS: My world continues to be focused on hiring as a pretty core aspect of things. We have happily had one offer extended and accepted, so that's great. We've got a person who will be joining the team in a couple of weeks. That's very exciting. And we're continuing in conversations with some other folks. So I look forward to the place where I can be on the other side of this and have that team and be growing the team and not having to focus because hiring takes a lot of effort. It is something that I believe should be done as well as possible and intentionally as possible and then just outreach and all that. So yeah, I'll be fine with being on the other side of that. But it's going well, so that is nice. STEPH: That's awesome that you're making progress. Once you have hired your team, will you then add to the agenda to hire someone to help with hiring? CHRIS: I don't actually know if the organization, if the whole company has someone who's focused on hiring. I think that can make sense. Working through recruiters and things like that is something that I've seen in the past. I've seen it work for certain organizations. I've also been on the receiving end of plenty of obviously copy and pasted very generic "Hey, person, I saw that you do lots of Java and other enterprise code software. Would you like to come work with us?" I'm like, none of those are true, and I do not want to go work with you. But thanks, I still appreciate the outreach. [laughs] So I am intrigued to see how we think about it. More generally, this is something that you and I have talked about offline but the idea that you kind of always want to be hiring. We do have specific roles that we've identified that the budget has space for. But more generally, ideally, we're going to need to hire more people down the road, and that will happen at a particular point. But having those conversations, starting to talk to people, now planting the idea of like, hey, you're great, and I would love to work with you someday and just keeping those lines of communication open. Networking is perhaps what the people call it. I don't know; I've never felt super comfortable with that word, but I think it's that and being friendly and staying connected with people whose work I respect and would love to work with more. So that's part of what I will come out of this with is yeah, let's always be hiring in a certain sense. STEPH: I'm glad you expanded on it because I was just thinking I have specific ideas as to what always be hiring means to me and what those activities would include. So I was curious what it means to you. And I agree, I think it's a lot of networking. It's a lot of taking chats and social chats with folks and just talking about the company and finding out where they're at. And then one day, if it works out that then they want to make a shift, then you've already got that relationship that started, and they're already potentially interested in your team. I guess some of the other big stuff that comes to mind, too, is like thoughtbot we have the blog. I feel like that's always really helpful too. Like when you help somebody, when you publish information that then helps them in their career, I feel like that will then draw people towards you as well. CHRIS: Yeah, the thoughtbot blog and basically everything that thoughtbot does, the podcast here, or Upcase, or all those things were so incredibly helpful in the hiring. But I also know they're hard to spin up, is what I would say. The thoughtbot blog has I don't even know how many hundreds of thousands of hours maybe. It's weird to try and put a number to it. But I've written a handful of posts for it, and I'm not great at writing them. They take me way longer than they should, but they took many hours. And then I had wonderful peer review by other developers at thoughtbot. And so, the amount of effort that goes into the thoughtbot blog absolutely produces wonderful benefits. But it's not free by any means, and similarly, the podcasts or Upcase or any of those sort of things. Similarly, the one that's actually most interesting that I see a lot of organizations go for initially and then often walk back is open source. Like, oh, we have this internal library that we built to do something. What we'll do is we'll just package it up and share it with the world, and then it'll be great. And the maintenance burden and support necessity of an open-source project is so high. I've actually historically gotten into the mode of suggesting...when I was working with clients, they would start to mention this and be like, "Oh yeah, we think we'll open source this thing, and it'll be great." I'm like, "Are you sure, though? Do you definitely want to?" There's definitely a difference between open sourcing and just putting an idea out there is one thing that I would say. Can you just write a blog post that has code snippets but not reusable code that you have to maintain that people, unfortunately, I think unfairly expect responsiveness and maintenance over time? And what if you stopped using that technology? What if you stop using this thing, but your name is still attached to it? And people have expectations of what that looks like. Or people come in and say, "Hey, this is great, but I want to change it in this way." And you're like, "Yeah, but that actually doesn't work for us. That's not how we use it. But we would be on the hook to maintain that code if we accept your pull request." And so, as wonderful as open source is, I tend to be on the more conservative end of the spectrum of like, are you definitely sure you want to open source this? Is there another way that you can share this with the world? Can it be a conference talk, or a blog post, or something like that? But it is an interesting one. STEPH: Yeah, I've been a part of several teams that have started with that; let's start an engineering blog. And their hearts are totally in the right place, and I understand why they want to do it. But like you just said, there's a cost to that. And if you don't have something like thoughtbot has like an investment day or a time for engineers to then be able to contribute to that blog, then either they're just not because they're not going to have their downtime to be able to do that. And it is hard to write and publish and be happy with what you're going to publish with the world. I really like what you're talking about in terms of the maintenance burden because I can't remember if it was an Upcase conversation or if there was something...but I was early on at thoughtbot and had a similar thought of why can't we just open source it? Why can't we make it public? And there was a very big thoughtful discussion around well, we have to have all these considerations in place. Who's going to maintain it? Just like FactoryBot is a really big internal project at thoughtbot. And there's typically a rotation of folks who will then take ownership and then onboard other people who are interested in it and curate the issues. And it's very important work, but you have to allocate time for it. All of that to say, I totally agree. There's a big burden that goes with it. CHRIS: Yeah, it's interesting that this has been an evolving thought in my head, and it makes me sad is another thing I'll say about it. I wish it were easier to just put code out there in the world and have the expectations properly calibrated for like, hey, I did this thing. Here's a code sample. It worked for me. Actually, I found dropping something in a Gist...a Gist just has a point-in-time connotation to it that I like. Like, if I see a code sample in a Gist, I'm like, I have no expectation that that person is going to do anything or respond to anything I have to say. But this is great because I now have this sample code that helps me get a little bit further. And I may have to vendor that code or take it on myself, and I now own it. It's not this person's responsibility. But the minute you have a repo with a README that says stuff and like, here are the installation instructions, the expectations just flip in a way that I don't think is...at least I become cautious around. And that does make me sad, though. STEPH: Yeah, it feels like you went from offering an example to I'm offering a product. And so then as soon as people feel like, oh, you're giving me something as a product that you maintain, then I'm going to have higher expectations of it should work how I expected it to work. I'm going to ask questions. And yeah, you make a lot of good points. CHRIS: Would you like to pay me $0 for me to build software for you? That sounds fun. STEPH: [laughs] CHRIS: And open source is such a wonderful thing. And so I'm interested in...like, I follow a lot of folks who are in the open-source world and have found ways to make it make sense financially or otherwise or organizationally. Open Collective and things like that is one option or OpenCore and then paid pro models and things like that like Sidekiq as an example. Sidekiq just celebrated ten years with some wild numbers in terms of the revenue, and it's like, yeah, that's fantastic. This is a cornerstone piece of software in the Ruby and Rails community. And also, Mike Perham had a great outcome from it. I think that's a win. So maybe blogging, maybe, but not sure. Probably not open source is my suggestion, at least for me. But one thing that I am interested in that hasn't been an option in my mind for a long time, but I'd love to get back to is conferences and going there, especially with a small team from an organization. The three developers we go, and we hang out at a conference and the company has a space there. And there's room to have conversations and meet people. That is one that I would love to continue in a way of making sure that our name is in people's minds as a place that they could work in this world. It is interesting, though, that it gets scoped a little bit like we are definitely a Rails shop. But that's not all that we are, or that's not the complete totality of our technical identity, so it becomes interesting. But I think it's probably the most representative. And I definitely see the Ruby and Rails community is having a good product-centric mindset that is definitely the sort of thing that I want in the teams that I'm building. STEPH: Yeah, I think that's an awesome idea because it's a way that you could focus on creating content. It'll likely have a big impact. But then you can also replay that content, but it's not the commitment of a blog or a commitment of open source. CHRIS: But yeah, so hiring has been, I would say, most of what I've been doing. One other thing that was fun this week, so I have my new laptop that I've had now for a couple of months, I'd say. And just this week, we had a very frustrating issue where Heroku stopped deploying our application. Just one day, it was like, nah, it doesn't work anymore. And I was like, well, that's less cool than I want it to be. And so one of the developers on the team dug into it, and it turned out Node-sass was the answer, which we're not even using is extra unpleasant. It's just part of Sprockets and Webpack or something like that. There's some downstream dependency sequence. We're using Tailwind and PostCSS. So we don't even need Node-sass. I think maybe PostCSS does. But anyway, turns out Heroku had switched to using version 16 of Node just without telling us. We were previously on 14, and then Node-sass didn't build on that. There was just this weird dependency chain that stopped working one day. And we weren't pinning the Node version within our application. So one of the developers figured this out, pinned us back to version 14 something of Node, and that was fine. But then my computer got confused because the versions were out of sync. Anyway, asdf is great. That's the first thing I'm going to say. So I use asdf to manage the versions of Ruby, and Node, and Yarn, and Elm, and basically everything else that I use. And I love that it's all under one hood, so asdf, wonderful. Also, my laptop, wonderful. I really love the M1 fancy laptop. But what was fun was I had to install the new Node version. And this was the first time in the three months I've had this computer that I've heard the fans come on. Finally, I asked it to do something hard enough that it was like, whoa, whoa, whoa, I'm going to need some backup here. And so the fans finally kicked in. So I don't know what's going on installing Node, but good for everyone involved, [laughter] impressive to make such aggressive use of all of the hardware in my computer. STEPH: Yeah, I love asdf. I miss it right now because I'm on my client machine, and we're not using asdf. Instead, we are using Chruby, C-H Ruby to manage Ruby versions. asdf is awesome. That's fun. It's the first time that the fans kicked on. I'm intrigued with my machine. I haven't really paid attention to it when the fans kick on except the one time where I had like a Ruby process that was running away, and I had to figure out what was going on there. Because then all the CPU was just being dedicated to Ruby even when I wasn't using Ruby. But since then, I haven't heard the fans. It's been very, very quiet. It's lovely. I like when it's quiet. CHRIS: Oh, it's been great. It was interesting because it was this weird noise that I'd forgotten about. STEPH: [laughs] CHRIS: My previous computer was so old that this was happening regularly whenever my backup process would run. Apparently, that is a very computationally intensive activity. So I would hear the fans kick in, immediately go find the backup process and say pause for 60 minutes or whatever it was. Just like, leave me alone. Stop it. The computer is getting too hot. You need to calm down. But now, with the new computer, there was nothing I could do to make it happen. And then finally it happened, and I was like, oh yeah, I guess this computer has fans. That's neat. But yeah, so things that are great, asdf and the M1 laptops. STEPH: Nice. Yeah, you're one of the few individuals I know that's using one of the M1 chip. So it's been reassuring to hear how well it's going because I did not opt in to that new-new. I opted in to the give me something stable and steady that I know so that way I don't have to fuss with it because I can then fuss with all the other things that I need to fuss about. CHRIS: So much fussing to do. STEPH: Lots of fussing. Fussing and cussing is what I do over here. CHRIS: [laughs] Mid-roll ad Hey, friends, let's take a quick break to hear from today's sponsor, New Relic. All right, so you've probably experienced this before where you're just starting to fall asleep, and it's a calm, code-free peaceful sleep, and then you're jolted awake by an emergency page. It's your night on call, and something is wrong. But I have some good news because you have New Relic, which means you can quickly run down the incident checklist and find that problem. So let's see, our real user monitoring metrics look good. And that's where New Relic measures the speed and performance of your end-users as they navigate the site. But it looks like there's an error in application performance monitoring. If we click on the error, we can find the deployment marker where it all began, roll back the change, and, ooh, problem is solved. We can go back to bed, back to sleep, and back to happy. That's the power of combining 16 different monitoring products into one platform. You can pinpoint issues down to the line of code so you know exactly why the problem happened and can resolve it quickly. That's why more than 14,000 other companies, including GitHub and Epic Games, use New Relic to improve their software. So you know that next late-night call is just waiting to happen, so get New Relic before it does. And you can get access to the whole New Relic platform and 100 gigabytes of data free forever. No credit card required. Sign up at newrelic.com/bikeshed. That's New Relic N-E-W-R-E-L-I-C .com/bikeshed, newrelic.com/bikeshed. CHRIS: Well, speaking of, what have you been fussing and cussing about this week, Steph? STEPH: So this is more in the pranting area, which is our portmanteau for praise and rant, where I'm super excited. I have a delivery coming from Amazon today. So I'm that person that keeps checking and waiting for it to show up. But I'm finally going to have one dongle to rule them all. I have a very messy approach right now [laughs] where I have all the dongles and have to plug everything in. And you know what? Normally it's fine. It's fine because I do it once, and I don't have to mess with it that much. But because I now have my thoughtbot laptop and I have a client laptop, and I needed to be able to switch back and forth, it is just too much. And I was realizing how many dongles I'm having to use. So I have one dongle to rule them all. It's showing up today. It's a very exciting day. CHRIS: I'm very excited for you. I recently made a similar switch when I got this new laptop. I was like, you know what? I'm going to look into it because power can come over USB-C and whatnot. And I was like, all right, it's finally time. I want to be able to just click in. And it's one of those things that feels trivial, or at least in my mind, I'm like, this doesn't feel like it'll make that big of a difference. But it makes it so much easier to disconnect my laptop, go somewhere else, and then come back. And I noticed myself doing that more, which I think is a positive thing. Otherwise, I'm just anchored to my desk. I'm like, I don't want to unplug everything and then have to replug it. That's like a whole thing. But now that it's not, I am more mobile, more flexible in where I'm working from, and I found benefits from that. So I'm a fan. I'm very happy that this is going to show up for you [laughs] and really change the way you're working. STEPH: Well, I've started moving away from a lot of Bluetooth connections as well because my keyboard will support Bluetooth, my headphones support Bluetooth. And I liked the idea of being wireless. But then, especially from switching laptops back and forth and then having to reconnect and all of it, it was just too tedious to go back and forth. And yeah, I'm with you where I didn't want to have to leave my desk and unplug everything and then bring it back where I'm playing, you know, like the game Operation where you had to reach in and then you had to grab different little bones? If you don't know the game Operation, that sounds really weird. But it felt like a game of Operation where then I was having to find all the dongles and connect them and plug them all in. And yeah, so it's going to be wonderful. CHRIS: Even knowing the game Operation, that still sounds kind of weird. STEPH: [laughs] CHRIS: But I really love that there are people out there listening that are like, what are they talking about? STEPH: What weird childhood did you have? CHRIS: Yeah, I'm definitely Team Wired-Almost-Everything. The only thing that I have that's wireless is my headphones. And it only works kind of, and I have to trick them sometimes. And the worst thing is occasionally my computer will have control, whatever, they're connected. So I'm listening to music on my computer and then suddenly, my phone will just steal it. It's like, what are you doing? No. Or, randomly, my headphones will be sitting away from me, and they'll just connect. And I'll be in the middle of a call on something else. Like, I'm here talking to you, and suddenly my headphones are like, hey, we wanted to join the party. It's like no, absolutely not, [laughs] not at this moment, under no circumstances. So I don't really believe in Bluetooth as a technology. I'm very much a fan, particularly with things like keyboards and whatnot. Bluetooth I've yet to be convinced that it is a sound technology. STEPH: I have the headphones where they try to be very smart, and they are pretty smart where they will block out sound. But then, if I am talking, then it will put me in more of an auditory space where then I can more easily hear, and it won't filter out sound as aggressively. But I've noticed a problem. And it's when I'm watching anything that's funny that then I'm laughing. So every time I laugh, my headphones think I'm talking to someone, and then it will switch over to where it's trying to let me hear more sounds out in the universe. And then it kicks back on because it's like, okay, she's done talking. It's a very jarring experience. [laughs] And I haven't figured out how to turn that setting off. It's like, oh, I just can't watch funny stuff with my headphones right now, which is also problematic with pairing because I tend to laugh a lot with pairing. It's a thing. I'm working on it. The struggles of Shteph. CHRIS: Well, at a minimum, it sounds like your dongle life is going to be improving very soon, and that's exciting. STEPH: Dongle life, it'll be single dongle life. That's it. [singing] All the single dongles, all the single dongles. Put your adapters up. [laughter] On a different note, talking about some of the work that I've been doing this past week with Joël Quenneville on our client work, is that we have been looking for ways that we still want to build up CI time. We've talked about the fact that we're working on some of that horizontal scaling. And I don't have an update there. But the other update I have is where we want to be very strategic about where we invest our time because improving the test is not trivial work. A lot of the low-hanging fruit has already been done, so triaging a flaky test can be very difficult, and it can take us a while. So we just want to make sure and verify that before we invest a lot of time into a portion of the test that then we know what the outcome is going to be. Are we improving developers' lives by this much? And how do we measure that? Are we reducing the CI build time, and how do we know that? And one of the areas that I really wanted to focus on is FactoryBot because there are a lot of factories. The factories tend to do a ton. So they are calling out to the database and building a lot of associations. And that's something that the team knows about as well is that there are just so many SQL queries that get executed in tests. And it would be great if we could reduce the number of SQL queries that are going out. And FactoryBot includes some ActiveSupport notifications, which means you can subscribe to factories being run which then gives you access to details like which factories are being used? What build strategy is used? Are you calling build build_stubbed or create? And the factory's execution time. So then the idea of this is that if we can harness a lot of the data that we can collect from FactoryBot, then can we ask questions around what's our slowest factory? How long does it take, and how many places is it being called? Because then ideally, we can calculate to say, okay, if this factory takes this long and it's used in this number of places, then we can have a formula to figure out how many minutes of our test suite is spent just on executing that factory. And then if we can reduce the time of that factory, let's say by half, then we know how much time we're shaving off of our CI build. And then we have this more concrete verified okay; this is worth our investment. We want to pursue this, even if the factory may take us a full day to improve because it does so much. And it's just gnarly. So it's going to take some time to really refactor it into a more simplified state. So, in theory, this sounds really, really great, and it was a lot of thanks to Josh Clayton, who was the one that advocated saying that we could use the ActiveSupport notifications to find a lot of this data. And so Josh and I paired on this for a bit to look into can we answer some of those other questions as well? And we were testing it on a small side project that he had, which was great because the other codebase is very big, and feedback is just a lot slower. So we wanted to first prototype it and have a proof of concept in a very quick space and just to be able to look through the data and make sure the assumptions that we had and the value would be there. So we applied that first, and that was going really well. And then Joël Quenneville took that strategy and then applied it to all the specs in the spec models directory and ran it for the much larger client codebase and got some really great results. And we also used a low fidelity approach where we wanted to be able to see which factories were the most popular. So how often are they getting called? And the average execution time. So that way, we could then quickly look at this scatter plot, and then we could see, okay, who's in the far upper right quadrant? Because those are the factories that are causing the most pain. But we started looking into a graphing library and what are we going to pull in. And Josh had the great idea. He's like, "I wonder if Google Sheets has a scatter plot. Can we export this to CSV data and then copy it from the terminal and import it into Google Sheets?" And it turns out that you can. So then we grabbed it and put it in Google Sheets and then just converted it into a scatter plot, which was really nice because then we didn't have to incorporate any chart library or any graphics or anything. We could just plop it into Google Sheets and then easily share it. So we now have this list thanks to Joël because he ran it through the spec models directory of all the factories that are getting called. And it's really interesting. And there's one, in particular, that is high on the list. And it was actually one of the first ones that we worked with when we were troubleshooting a test that took us a while when we first joined the project. And the average time for this factory is four seconds, and it gets called over 500 times. It's like 527 times. So then if we multiply that, so if we say, all right, it takes about 4 seconds times 527 and then divide it for 60 for minutes, that's 35 minutes, 35 minutes for that factory. Now, granted, these are getting parallelized across different processes. But still, if you divide that up across four processes, that's a non-trivial amount of time. So I think this is going to be really helpful and really interesting data that we can then use to drive our decisions to say, okay, we want to take this factory and let's say even if we can cut it into half, let's say if we bring it from 4 seconds to 2 seconds, it'll go from 35 minutes to 17 and a half. CHRIS: Oh wow, I love the methodical approach. I love that actually having a number you're like; this is how much pain or the cost of this right now. And so we've identified that this is this high-level thing. I love the intentional starting with, like, let's measure it. Let's understand where the most bang for the buck is. In particular, the graph that you're describing reminds me of one I haven't actually worked with it much. But Code Climate has a graph that they use, which is it's churn versus complexity. So it's like, you may have a very complex piece of your code, but someone wrote it once, and it just sits in the corner. And you know what? It quietly does its job. And yes, it's very complex, but nobody needs to touch it. So it's not a big deal. And then you have stuff that changes constantly, but it's super simple, so that's fine too. Your UsersController is probably going to change a bunch; that's fine. But the stuff that is constantly changing and very complex that's the magic quadrant that, like, pay a lot of attention to that. And similarly, which are the ones that are being used a lot and take a while? That's the magic quadrant. I'm intrigued now. I want to search for more magic quadrants that deserve attention. But for now, that sounds like a lot of fun. So now, what's the approach that you're going to take? I imagine you need to alias that factory and have it exist because some tests will rely on certain details of it. This is my guess. So let me see if this is the way that you're thinking about it, alias the factory, so you have a representation that does all the stuff that the current one does. But then you have a new one that is much more pared down. And then, on a test by test basis, you start switching it over and trying to move things to the lower weight, the slimmer version of the factory. But I would think you would want to do a gradual process if there are 520-ish usages. Because otherwise, just changing that factory out from under all the tests, I imagine you'd break some tests if you just were like, what if it did less? STEPH: Yeah, I like that idea of the incremental approach. And that all sounds great, especially the alias because you're right; we want to change it incrementally and not all of them at once. But then essentially implement, one, because I want to see what does the pared-down factory look like? What is the basic factory that we can get away with? And then how long does it take for that factory to execute? Because then that will help confirm, can we really get it down to two seconds? Or is this just a factory that's always going to take three and a half seconds, and then it's not really that much of a payoff? Maybe we should look for a different factory to investigate. And then also understanding from the test are people reaching for this factory all the time because it builds up the world and all of these tests need the full world? Or are people just reaching for this because it does the one or two things that they need, and we can get away with a much slimmer factory? So right now, it's in the space of understanding why are people reaching for this? What are the tests they actually need? And yeah, how can we do it incrementally? At one point, we may even be able to try to programmatically switch it out. Maybe we just find 50 tests that are using this once we have the slimmed-down version and we replace...50 is probably too big. But if we replace X number of tests with this factory, how many of them fail? Maybe 10% of them passed. Cool, let's just take those 10% as a win and issue those as a PR. So that could be a strategy as well just to find if there's any that are super easy to change. All we had to do is literally change the name of the factory. The other big part that's on my mind is education around factories. I think a lot of people on the team understand that factories are very important. They can be very helpful. They can also be very cumbersome. But it feels like a good opportunity to say, "Hey, we are specifically working on these factories. Here's the reasoning that led us to work on these factories. When you're in the space of factories, please be mindful about what are you reaching for? Is there a slimmed-down factory that you can reach for? Maybe you can implement your own slimmed-down factory if one doesn't already exist." So I like the idea of coupling it with also just broader awareness because we are but two people. So I would love for more people to be part of the changes. CHRIS: Unsurprisingly, there are some wonderful blog posts on the thoughtbot blog that speak to this topic. One that I'm a fan of is Factories Should be the Bare Minimum. This was written by Matt Sumner. And it describes basically that idea of factories shouldn't build the worlds. They should give you the pieces that you can use to build the world but not build the world entirely. And so I'm a big believer in that, having your factories be as minimal as possible. They should be valid, but that's about it. And then I will often reach for extracted helper methods and keeping those as locally scoped as possible often in the spec file, or if not, maybe they're sharing spec support. But being intentional with where we reach for them and not having everyone use the same thing that just slowly gets added to. And it's like, do I actually need everything that's in there? The other thing that's interesting is the idea of having a factory that does a ton is, in my mind, sort of in direct contradiction to what I believe factories exist for which is when I think of factories, they're useful to fill in the rest of the details such that you don't have mystery guests in your test. But you can explicitly say build me a user who has an email that looks like this because, in this test, I care about the email, but I don't care about the rest of the details. I don't care about their name. I don't care about their password, or the roles, or any of the other details. Just let the factory deal with that because it's not important to the test. But I want to make sure that the relevant detail is present and specified within the spec. If you have a factory that builds everything in the world, that's like build a user and then grabs the first action from the project that that user has, because I know that they do because they use the big factory, that is just in direct contradiction to what we want factories to do. We want tests to tell their story. We want to avoid mystery guests. Factories are a great way to do that while still remaining concise. But if your factories just build the world, then there are some mystery guests in the world, I can assure you. STEPH: Yeah, I agree where factories have served as an abstraction for what I think is important to the test. But then there becomes this moment of where someone thinks, well, I need to build up these records, but I don't really need to reference them directly. I just have some coupled code that's going to rely on these. And so I don't explicitly need them, but they need to be there. So I'm going to extract it away, and a factory feels like a good place for me to extract that too. And I would take the very hard opposite approach where if you have coupled code and you have these dependencies that aren't necessarily explicitly used in the test, but they are required for the test, I'd rather see a painful test setup than have all of that extracted away from me. Because then if I do need to triage or troubleshoot that test, it's going to take a lot of just mental overhead to work through what do I actually need here and why? So I'd rather see that painful test set up then have it moved somewhere else. But I think a lot of people take the opposite approach of where if I abstracted away, my test looks prettier. And I'm like, yeah, but maybe to you in the moment, but it's going to cause me a lot of pain further down the road when I have to work with this. So show me all the crap that you had to do upfront. Just let me know. [laughs] I'd rather the test be honest with me. And then it's a really nice jumping-off point because you can see a test that does all of this. And instead of blaming the test and thinking it's the test's fault, you recognize this test has a lot of complicated setup, and it's probably because of the code and how the code was written. And we should look at refactoring the code, not at how can we make our tests look prettier? CHRIS: Unsurprisingly, I agree with 100% of that. Someday we'll find things other than Pop-Tarts and IPAs that we disagree on. But today is not that day. [laughs] Once again, today is not that day. Mid-roll Ad Hi, friends. And now a quick break to hear from today's sponsor, Scout APM. Scout APM is an application performance monitoring tool that's designed to help developers find and fix performance issues quickly. With an intuitive interface, Scout will tie bottlenecks to source code, so you can quickly pinpoint and resolve those performance abnormalities like N+1 queries, slow database queries, and memory bloat. Scout also recently implemented external service monitoring, adding even more granularity when it comes to HTTP requests and API calls. So give Scout a try today with a free 14-day trial and experience first-hand why developers worldwide call Scout their best friend. And as an added bonus for Bike Shed listeners, Scout will donate $5 to the open-source project of your choice when you deploy. To learn more, visit scoutapm.com/bikeshed. That's scoutapm.com/bikeshed. STEPH: Well, here's one more that maybe you'll agree with, maybe you won't. We'll see. I'll try not to lead you in either direction, but shared examples. If I'm going to rant for a little bit, shared examples are in that space of where they just get used so heavily, and they abstract away important information about the test. And it makes the test so succinct that I don't actually know what the test is doing. And I've seen a number of places where a shared example has been extracted, and it is only used within that test file once, maybe twice. And I'm just like, friends, too much abstraction. Please keep it close. [laughs] We don't need to move it away. We want our test to be friendly and just full of context, which is what I mean when I say friendly. I want full of context is what I'm looking for, well-named variables. And I won't be able to read the test and see what's happening. So my little complaint for today would also be about shared examples and how they can be overused. And they do have a really neat purpose. They can be helpful for if you're testing maybe a controller action and you want to say you're extracting that authentication, making sure that a controller always has authentication and then that is getting included. Sure, that feels very helpful. But that's really one of the few cases I can think of where a shared example comes into play. And if you are testing code over and over throughout different parts of your codebase, there's probably a part of your codebase there that needs to then be pulled out into a class and test that class in isolation. And then you don't need to retest it throughout all of your other classes. Have I already ranted about shared examples? I can't recall at this point if I have or not. [laughs] CHRIS: I don't think we have talked about shared examples before. And I appreciate you not leading the witness here. But I think I'm in agreement with you, particularly the way you refined it there at the end because that controller example is the one rare case where I might reach for it. But in general, I think this is one of those things that I saw early on in my career. I was like, oh, cool; this is a way to clean stuff up and DRY and all those wonderful things. And then I've definitely felt the pain of just overuse of shared examples and ways to pull details out of tests. But it's like, I want to see the details. And I think broadly, that's the theme that you and I are very aligned on is like, no, no, no, tell me the story in tests. I am much less interested in having these concise tests that have a single line, and it's like, expect foo to have bar. And it's like, why? Because...oh, there's a let and then a subject, and it's a shared...oh okay. Now that I can put it together, I can tell the story, but I cannot look at this test and see a story. I want to see a story, friends. So yes, I'm totally in alignment, especially with the slight caveat at the end of like, there are cases where it's useful. Similarly, I've used let. I definitely have not even that long ago. And I stand by the usage, but it was very rare. It's very rare, and it is something that I'll look at and be like, am I sure? Definitely, is this the right thing, or did I do something wrong? Because if I find myself leaning towards let, it's like there's something that I don't think is important to the story of this test that still needs to happen. Why is that? What's going on here? Something feels off about that. And similarly, with the shared examples, it's like, is there not a different way to extract this such that I can test it in a way that I have confidence in, and then we're good? I occasionally will talk myself into using shared examples or something like it where I'm like, oh, but it's really important that everything in the app has that authentication layer put in. And so, I should definitely have this very easily reusable test that can ensure that I have it. But there's a tautology there of well, if I write the test, then I'm definitely thinking about the implementation. But if I forget the implementation, I might also forget the test. And so, it actually doesn't provide any real safety. And in those cases, that's a rare case where I would reach for some weird metaprogramming thing that's like, controllers must do the thing. And we say that in application control and then everything inherited from that will raise if it doesn't implement the authentication layer. Something like weird code that says, "You shall not pass. You must, in fact, implement the authentication layer." Rather than saying, "Oh, we'll just make it really easy to test it so that we always test and, therefore, always use the necessary authentication layer." But yeah, that's a hard one to describe in the radio. So I don't know if that came through clearly. But that's sort of my headspace on this. STEPH: Yeah, and all of that makes sense. I'm trying to think of a good example. And it's been a while since I've used Pundit, but I feel like Pundit may have a really good example of this where it's very easy to document to say, hey, all of these controllers need to make sure that they call out to this class or that there's authentication. I can't remember the exact code and how that works. But I feel like Pundit has a really good example of that behavior. CHRIS: I think they do. It's something where I think it's a configuration level thing, but you say, "Hey, Pundit, we should definitely authorize any access to models." And so Pundit then has a before action, or it's an around filter one of those. But it will raise an unauthorized error, I want to say. Like, you did not do the authorization dance in this. And that's a great example of like, I like that it is loud and annoying and in your face. And it is not possible for me to forget it because we configured it throughout all controllers. And so it's that sort of thing that I would probably reach for even though that code gets complicated and messy, and actions at a distance. But it's worth that trade-off in my mind to have, like, I don't want to forget to do the authorization stuff. Permissions matter. STEPH: That was a really nice pre-emptive approach as well. Because in most cases that we're describing, it's the I'm going to write a controller, and then I need to add this test to verify and prove that yes, I didn't forget the authentication stuff versus upfront, you're setting in a configuration to say, "Hey, please remind me to do the configuration or the authentication step that I don't miss this." So that's also a really, really nice approach. CHRIS: Yeah, the same version of me that's going to forget to write the test is going to forget to write the implementation. So I don't want to trust that version of me to save that version of me. I'm equally untrustworthy in those situations. STEPH: You want to trust the version of you that's going to get yelled at by the code if you don't do it. CHRIS: Yep, I'm going to trust the version of me that was like, I don't trust any future version of me. I will yell at myself if I have not done the necessary things. STEPH: [laughs] CHRIS: To be clear, this is like a life philosophy of mine. I don't try to remember things because I forget stuff a lot. It just happens. And so if I need to take something out the door with me, it goes in front of the door but extra critically, and this is the subtle line. Because plenty of people do that trick where you put a thing in front of the door because then you can't leave without it. There's no way to forget it. But by virtue of that, you cannot put something in front of the door until it is time to use it. Like, if ever you have to go and be like, oh, I don't need it now, though, so I'm going to move it out of the way, open the door, and then leave. No, no, no, because then you've broken the magic of the thing in front of the door must leave with you. So it's a very subtle line. I will play games with myself. I'll be like, I am forgetful. I will not remember this. I do not trust future me, so I'm going to play a trick on them. But you got to calibrate it just right. STEPH: That's really funny because I totally [laughs] didn't think about it until now how you described it. But I have definitely done that where I set a rule for myself, but then I'll break it. And then, of course, everything all of it collapses. There is a time when Tim, my husband, was going through a developer bootcamp. And as he was learning the whole world and everything that's out there, he would ask me all these questions. And he's like, "Do you know this?" And I'd be like, "No." He's like, "Do you know that?" I was like, "No." He was like, "I thought you knew this stuff." He's like, "I thought this was your job." And I was like, "Yeah, I'm really good at finding it and Googling it. But I work really hard to not store this in short-term memory because I'm filling it up with other stuff. So I work really hard to be able to find this stuff and track it and Google it." But now, there's a lot of stuff that I try very hard to not hold on to until I need it. But that was a funny moment where he seemed very upset that I didn't know stuff. And I was like, "Well, welcome to web development. There is too much to know. You're going to have to have a really good catalog system." CHRIS: Also, just so we're clear, it's going to change by next Thursday, so don't hang on to anything like it's just true forever. STEPH: [laughs] CHRIS: SQL will probably be around. That's about it. That's the one thing that I'm really confident in. STEPH: Yeah, that feels fair. Get really good at understanding HTTP forms, SQL, all that feels like some really good groundwork. CHRIS: There are some foundations. We should have a foundations episode where we talk about what we think the foundations are, the stuff that we bet won't be different in 10 years. But everything else is going to change by next Thursday, specifically. STEPH: Yeah, I like the idea of foundations. I'd be intrigued to see what we talk about and what happens there because I feel like that's going to be very representative of already what we talk about. We often will sprinkle in some new-new, especially thanks to a lot of the adventures that you go on. But I feel like a lot of the stuff that we talk about we always bring it back to the foundation because we do want the experiences that we're having to be applicable to everyone else as well. So yeah, that would be interesting to see what comes out of that. On that note, shall we wrap up? CHRIS: Let's wrap up. The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeeee!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

The Bike Shed
325: Pranting

The Bike Shed

Play Episode Listen Later Feb 8, 2022 35:12


Steph is super excited about changing her schedule to dedicate a full day to focus on being a great team lead. Chris talks about his continued adventures in the world of hiring. Together they answer a listener question about what they consider a “large” table in a database and how they review schema changes. This episode is brought to you by ScoutAPM (https://scoutapm.com/bikeshed). Give Scout a try for free today and Scout will donate $5 to the open source project of your choice when you deploy. Services down? New Relic (https://newrelic.com/bikeshed) offers full stack visibility with 16 different monitoring products in a single platform. ClickHouse (https://github.com/ClickHouse/ClickHouse) Timescale (https://www.timescale.com/) InfluxDB (https://www.influxdata.com/) ddl-partitioning (https://www.postgresql.org/docs/current/ddl-partitioning.html) Become a Sponsor (https://thoughtbot.com/sponsorship) of The Bike Shed! Transcript: STEPH: I just feel like every time I listen to Celine Dion, there are lots of dramatic hand gestures that have to go with it. CHRIS: Yep, definitely that. I'm strong team Power of Love. STEPH: Ooh, yeah, yeah, that's a good one. CHRIS: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Chris Toomey. STEPH: And I'm Steph Viccari. CHRIS: And together, we're here to share a bit of what we've learned along the way. So, Steph, what's new in your world? STEPH: Hey, Chris. Oh, I have some exciting news. I am changing up my schedule. It is going to start next week, where as a team lead at thoughtbot, we have been working on finding ways that we can have more time to invest into the team and team-specific initiatives. And most of us spend four days billing on client work, and then we have investment day, which is delightful. But we're finding as team leads, that's really not enough time to then have the impact that we want in terms of supporting our team and then also having time for mentorship and all the other things that go along with being a team lead and one on ones. So we have been incrementally working towards reducing billing. So team leads only bill three days a week, and then they have an additional day to really focus on being a great team lead. And I start that new schedule, that new-new schedule next week, and I couldn't be more excited. I think it's going to be wonderful. I do think there are some challenges that go with it in terms of really balancing, at least this is from the others who have gone before me where they then find it a bit harder in terms of client expectations of saying, "Well, I was billing four days, and I had a larger impact on the codebase and the team. Now I'm dropping to three days. I still need to stay within that constraint. And I want to keep the client team happy." So that seems to be a thing. But I will find out next week how it goes. CHRIS: Well, I'm very excited for you. That sounds wonderful, frankly. The balancing of the client expectations and then there's sort of now three slices to your work, which there always were, but now you have it delineated in an interesting way. Do you have specific plans for the team lead? So let's say now, nominally, there's one day a week that is dedicated to team lead time. Do you have ideas of what that looks like? Are you planning to pair with your team? Is it longer one on ones? I don't want to seed the question too much with potential answers. So what are you thinking about there? STEPH: [laughs] Ideas are great. And yes, so I think number one is structure. So right now, one on ones and any support that I need to provide others is more ad hoc, or at least the one on ones those are not ad hoc; they are structured. But they are spread out throughout the week, and then I just context switch between client work and then checking in with others. Now I can stagger everything on a Thursday or whichever day is going to be my really focused team lead day. So that way, I have all the one on ones on that day. And then yes, I can have more time to pair. So I can say, hey, let's just schedule every other week where you and I hang out, and we pair for an hour, and it can be on their client work. It can be on anything that they'd like to work on. Or, if there's a particular topic they'd like to talk about, we can pair on consulting issues or discussions. But yes, ultimately, I'd love to do more pairing and then structure one on ones to a specific day and essentially, just really protect that time. Because right now, it feels that client initiatives and work always come first, and then team lead comes second. And I'm excited to balance that more so they have equal priority. CHRIS: Yeah, that sounds great. I'm super intrigued to see what specific structures fall out of it and how you're experiencing it. I'll be interested to hear how investment time changes for you as a result of this because I remember when I started in the management role, four days a week billing, and then one day a week of investment time. But the investment time then basically went to one on ones and other things like that. And when I switched to a three-day week, I was able to reclaim some amount of investment time. And it was interesting having that open back up and have that be a consideration. Because definitely one on ones and things like that I think firmly fit within the idea of investment time or investing in the organization and whatnot. But still, there's the like; I'm going to go explore a new framework or something like that that also certainly fits within investment time. So I'll be interested to hear if you find that changes in sort of a specific way. STEPH: Yeah, I'm really interested in that as well. Because right now, as you mentioned, my investment activities are really focused more around the team and other folks and then Bike Shed. Bike Shed is a really big investment time activity. So I've noticed since becoming a co-host for the show, I talk a lot about code, but I don't necessarily contribute to open-source projects or other internal projects at the rate that I used to. It's now more focused about here and being a co-host and talking about all the things, and that requires some prep for me. So I'm also interested to see if this will shift my investment time a bit where I do find a little more time to code and then explore just things that I'm interested in. But in the experiment of doing something new, it's always important to then have a way to measure is this a good change? Is this a bad change? So we have been checking in with team leads to say, "Hey, we've changed your schedule to where you're billing one day less. How's that going for you?" Because there's the assumption that this will be great, but you really have to check in with folks to find out. So Edward Loveall has been sending out a helpful survey and checking in to say, "Hey, how are you feeling about your client work? How are you feeling about your team lead responsibilities? How are you feeling about investment time?" So then you can track your own growth and see is this really helping me? Is this really going in the right direction, or am I just more stressed about everything now? So that's helpful that we are also just looking back to make sure that this is supporting the initiatives that we said it would support. But that's some of the newness in my world. What's going on in your world? CHRIS: What's going on in my world? Continued adventures in the world of hiring. So we've got a couple of people in the pipeline now. We've got some folks in the technical interview phase, which we're structuring our technical interview very much inspired by the thoughtbot interview. So it's a pairing session as well as some code review, which is great because I think it's really representative of the actual work that we do. I believe strongly in not having an interview that is trivia or anything of that sort of thing. I want to see folks at their best as opposed to finding the rough edges. Because I think it's critical to have an interview that really represents the work that we're doing and then also gives candidates an opportunity to show themselves at their best as opposed to trying to hunt out gaps in knowledge or things like that because I think it's easier to shore up a gap of knowledge. But I really want to know what is this person like when they're firing on all cylinders? So, so far, that's going great. But hiring is a complicated long game. So it will probably be a thing that I'm talking about for some weeks to come. And if anyone out there is listening and is potentially interested in a new adventure, I would love to chat with you. Sagewell Financial is hiring. And it's a wonderful Rails codebase and lots of new opportunities, et cetera, et cetera. STEPH: As someone that has worked with you, I can absolutely vouch that you are amazing to work with. And I can only imagine the codebase must be...everything we've talked about is really interesting and stellar. So yeah, I love that you're talking about this. I think it's awesome and a great opportunity for folks to get to join Sagewell. CHRIS: Oh, thanks, Steph. That's very kind of you. But in other unrelated to hiring news, one of the things that I talked about in last week's episode was my search for a new to-do list or a new application to use. And I listed some of the ones that I've been exploring. We got more feedback about that particular segment than any other by like 2X. And there's something to be said there. Maybe the show is just living up to its name. But so many people are reaching out like, "Oh, have you looked at this one?" And to be clear, I very much appreciate all of the feedback that folks have given. And actually, it has given me a few new things to look at or ways to think about this question. But mostly, I find it very funny that even though we've dabbled in topics like agile, and is it good or bad? Or other contentious ideas [laughs] like that, somehow this idea of what to-do list application should I use by far the most engagement we've seen with our audience. STEPH: I think it makes sense. Everybody has an opinion. Like you said, we're living up to our name, which is great. Was that great? I don't know. [laughter] CHRIS: It's something, I'll say that. STEPH: It's something. But yeah, everybody has felt this pain. They get it. It resonated. But since we do have some people that shared their strategies and their thoughts, did that sway you at all? Are you still going to keep with what you have, or are you going to explore new things? CHRIS: I consider this project open. I have a project in Things, which is the current to-do list application that I'm using to explore the landscape. But it's basically like, I want to timebox it, find a version that works for me. And right now, I moved to Things, and it's fine. I'm more intrigued by the jobs to be done aspect of it. So as opposed to a particular piece of software and the features that it has or doesn't have, I really want to think about the habits and workflows that I want to make easier and more repeatable. So particularly, each day, I want to wrap up by cleaning everything up. I like my inbox zero, as you probably know, so doing a little bit of that, and then planning the next day. So I want to have a tool that supports that idea of I want to queue up what I'm going to do in the morning so that tomorrow morning when I start back up, I have a very clear list of things to do. And I can just dive in with what I find to be some of my best thinking time early in the morning. Similarly, I want to be able to review on a regular basis and know if things are getting stale or overdue. So there are a couple of different workflows that I'm really focusing on. And it's unfortunate because then I look at each piece of software, and I'm like, well, you kind of support this but not totally. So I'm more in a collecting phase right now. I'm thinking about the workflows that I want to have and then finding the different tools and comparing them across those. But the one thing that I have done at this point is I wrote a little Siri shortcut I think is the name for it. They're called Shortcuts is the name of the application, but if I try and Google that, Google doesn't really know what I'm talking about. They think I'm talking about my phone, but I'm not talking about my phone. I'm talking about my actual computer, but it's little workflow automation stuff on OS X. And so I have a shortcut now that prompts me for the amount of time, and it defaults to 45 minutes. And then, it will turn on Do Not Disturb for 45 minutes, minimize Slack, because I can't be trusted, and turn on a particular Spotify playlist. And then there's a little menu bar application that...I wrote a tiny bit of AppleScript; I found it on the internet and actually read it, that finds the top task in my to-do list and puts it in the menu bar. And so now I have all of that. I push a magic button, and I say, "Yes, so I would like to work for 45 minutes on the thing that is at the top of my to-do list.” And then all of the noise of the world goes away for 45 minutes or however long I say. STEPH: I think you just created the next new hot to-do app. [laughs] This sounds like something that I need and love, especially when you're like, it autoplays a playlist for you and shuts down the world and then has you focus. Yeah, I like this. I think this also rings a bell. I feel like Momentum, or something also has similar prompts. But this sounds delightful. CHRIS: If we're being honest, it's an absolute hodgepodge of a kludge. You have some weird shell scripts and some AppleScripts. And I had to install a weird command-line utility for Spotify to make it happen. But it was one of those like; I'm spent at the end of the day. I just want to tweak on some piece of code. And this was a perfect, productive distraction, is how I would describe it. And when I've used that, I've been very happy. I know the days that I actually lean into that mode of working are better days. The days where I allow myself to be distracted by Slack throughout the day, although I'm responsive to certain questions, things are not moving as well as they should. And so, I'm trying to be really intentional with having more of these Do Not Disturb sessions throughout the day. I feel bad saying that. I shouldn't because we all should be in agreement that this is the way that we work. But even saying that, I'm like, I'm not that special. I should be reachable, right? [laughs] But I should take even just a short 45-minute break to focus on the work that I actually need to do. It's a struggle. STEPH: I have struggled with that where I used to always feel such an urgent need that I had to respond to someone as soon as they messaged me. But over time, I've learned that one, things typically aren't as urgent as I will feel that they are. And then two, if you have that type of environment where people aren't expected to just immediately reply to stuff, then you learn to write things in a way that says, "Hey, when you see this, and here's context, and here are the things that I'm looking for. And here's an easy way for you to give feedback." It just improves the overall communication. I could go on a rant about this. I think we've actually ranted about this before in a very positive way. [laughs] Yes, I think that's great that you are fighting the good fight and turning off the world for 45 minutes to focus on a task. CHRIS: What's a positive rant? I feel like there's got to be a word for that. [laughs] But I'm trying to try and come up with that. A celebration isn't...is this one of those gaps in language where we don't have a word for a positive rant? STEPH: Oh, this is going to bother me. [laughs] There's got to be something for a positive rant. CHRIS: Well, I'm sure German has...some Scandinavian language or German has a more specific version of when one goes off on a rant for many hours about things that they love and are joyous about in the world or something like that. But maybe English is just lacking this, or maybe this is a market opportunity. And we can coin the word, and then it's ours. STEPH: I think it's just praise or accolades, although that doesn't feel strong enough. Rant feels like such an emotional word that I agree praise doesn't feel strong enough. CHRIS: It's also spacious. You don't just rant, and it's one word. It's not just like one swear that you yell in the word. No, it's this long rambling thing, and I want that but positive. Maybe it's just called The Bike Shed [laughter] because I think that might be what we do. STEPH: I love that. I'm trying to smash it together, and all that I can come up with is prant, so that leads with a P. CHRIS: Yeah, I went there real quick. [laughter] Portmanteau is where I spend most of my time. But prant is just not enough. Okay, we're going to take this offline. I think we should come up with a word. This is our market opportunity. I don't know that we'll make a lot off of this, but we'll have a word then. STEPH: It's okay. Free things are good. Oh my goodness, this is going to be so trivial and silly. But I've been playing Wordle as the rest of the world has. If you're not playing Wordle, check it out. [laughs] It's delightful. And it's free. But I started playing without really researching who created it and didn't have all of the details behind it. And then it was earlier this week I found out that the creator of Wordle is Josh Wardle. And that just blew my mind and made me so happy that it just had that alliteration and similarity. And I just hadn't put it together until that moment. And it was just this wonderful, happy bubble of a moment where I was like, oh, that's delightful. [laughs] And I'm pretty sure I texted some people who were like, "Yeah, yeah, we know that." [laughs] CHRIS: Yes, that was a wonderful positive rant or prant as it were there. And Wordle really is just such a delightful phenomenon that popped out of nowhere and is given away for free by the kindness of Josh Wardle. So yeah, wonderful things on the internet. Mid-roll Ad And now a quick break to hear from today's sponsor, Scout APM. Scout APM is leading-edge application performance monitoring that's designed to help Rails developers quickly find and fix performance issues without having to deal with the headache or overhead of enterprise platform feature bloat. With a developer-centric UI and tracing logic that ties bottlenecks to source code, you can quickly pinpoint and resolve those performance abnormalities like N+1 queries, slow database queries, memory bloat, and much more. Scout's real-time alerting and weekly digest emails let you rest easy knowing Scout's on watch and resolving performance issues before your customers ever see them. Scout has also launched its new error monitoring feature add-on for Python applications. Now you can connect your error reporting and application monitoring data on one platform. See for yourself why developers call Scout their best friend and try our error monitoring and APM free for 14 days; no credit card needed. And as an added-on bonus for Bike Shed listeners, Scout will donate $5 to the open-source project of your choice when you deploy. Learn more at scoutapm.com/bikeshed. That's scoutapm.com/bikeshed. CHRIS: We have a listener question this week. Once again, just as a reminder, everyone, we love getting these listener questions. Feel free to send them into hosts@bikeshed.fm or ping Steph or I on Twitter or any number of different ways. There's, I think, a form that you can go to the website, lots of different ways to ask us your questions. But again, we really love them. They let us have more pointed topics to talk about, such as today's topic, which is "What do you consider a quote, unquote, "large table" in a database?" Which is an interesting question, I think. And so, let me read the question here. "Hey, Steph and Chris, I've listened to you (and most of your predecessors) for a while now. I've really been enjoying the conversational style about your actual development struggles." Thank you so much. This comes from Matt, by the way. "Anyway, something Chris said in Episode 301 triggered a thought for me around large tables and databases and handling them for development tasks. What do you consider a quote, "large table" in a database? What questions/considerations come to mind when you're doing PR work that has a database interaction in it? We recently needed to delete a lot of rows out of a large table, and the team has a lot of discussion around how to handle it without impacting our production users. Curious on your thoughts. Thanks." So, Steph, what do you think? What's a large database table in your mind? STEPH: So I don't have a scientific answer for that, but I can give you my gut instinct. So typically, if there's a table that has a million or more records, I'll refer to that table as a large table. And then, if a table has around half a million records, then I start to be more cautious about data changes and how I'm rolling out schema changes. So that's my very loose; this is my feeling of when we're getting into large territory. How about you? Do you have more of a concrete answer? CHRIS: I don't. And I think it would actually, in a lot of cases, be defined based on the database system that we're working with and, frankly, the RAM available on that system. There are two different sides of it; one is on the right side, like, how quickly are we inserting data into this table? And how quickly is it growing? Is probably a better question. Maybe there's a ton of data in it, but it's not growing that quickly. And so, we don't need to worry about any runaway characteristics. The other side of it is how easily can we read from it? And that is the one that's going to be RAM-constrained. Where can we maintain an index efficiently? Can we query effectively and use RAM and whatnot? So a million starts to become an interesting number, probably. But I've worked on plenty of databases where hundreds of millions of rows existed, and we've got efficient indices in place and enough RAM that the database just happily works with that, and there are no problems. So really, it's a question of like, if we start thinking about having to need to delete data, then that's a large table. If we have one table that is wildly larger than the others in the system, then that is something that I'll keep an eye on. I want to make sure, like, how's that table doing? How's the special table doing? And often, there is one or two special tables similar to the idea of god objects within a system where these are the one or two classes that have just method after method after method after method. Similarly, there are one or two database tables that often have the lion's share of the data within the system. And so those are the ones that I'm really focused on. And especially as we get closer to the RAM limit, there's this drop-off that I've seen happen where a system is like, it's fine. We got 250 gigs of RAM; there's no problem. And our database is only 100 gigs. And then a couple of weeks later, suddenly, had a bunch of new users sign up, and suddenly, your data and your indices no longer fit in memory. And now we're paging to disk, and suddenly the performance characteristics of your system just tank. And so it's that sort of thing. Watching growth rates is perhaps more important than the absolute size of any individual table. So yeah, those are some loose thoughts. STEPH: I like how you used the word interesting. I think that's a nice replacement for the word large. When we get around a million records, things start getting more interesting in how we're rolling out schema changes. And then there's also you touched on usage, which aligns well with I often don't think so much about how many records that we have in a table. But what's the usage of that table? How many queries or transactions are being executed against that table? Is this a very popular table like the users table? And will running a migration that renders that table inaccessible for a couple of seconds will that be problematic, or is this a table that we write to a lot, but we don't read from very often? And even if it runs a couple of seconds, it's not likely to have an impact on people using the application. So that's one area I tend to think about first is what's the popularity of this table? And how cautious do I need to be in making sure that we don't block other people from accessing this data? I also really like how Matt asked the question about what considerations come to mind when you're doing PR work that has a database interaction? That's one of those areas that, honestly, I lean pretty heavily on Strong Migrations to remind me how I can rewrite a migration to avoid or to transfer a blocking operation to a non-blocking operation. So a really good example is setting a NOT NULL constraint on an existing column. I know that it can be very blocking if you try to do that by default when you first run it, and I will look it up every time. I will check Strong Migrations and say, "Hey, I know you've got some really great docs that will walk me through about adding a check constraint instead," and then making sure that I can then add this new column. So going forward, for inserts and updates will apply the default, but it doesn't validate all the existing data. It's also a really good reminder, that particular example, is start with stricter constraints because it's a lot easier to remove a constraint than to add one later. So that's one consideration that comes to mind. I also think the fail fast and fail loudly applies nicely here. So if I'm looking at a PR that is making a schema change, then I want to validate that the application has low timeout values so that way if a migration does take more than 30 seconds to run, then the migration will timeout. And then that will alert the developer to say, "Hey, do you need to think of a new approach or see if there's a way to improve this?" Versus if that migration didn't timeout, then that timeout is going to become user-facing as they start to experience problems with the site. And then also looking for more performant methods so using findnbatches, update all, delete all, just checking for the more performant ways that we can update large sets of data. Those are, I think, the top things that I really look for. How about you? CHRIS: Yeah, I think very similar to everything you just said. And broadly, there's a point in time that happens frankly pretty early on in the growth of an application and the data set behind it where you need to start behaving differently with regard to migrations. There's a small period of time where I can just get away with anything. I actually really love the part before we have any actual users where I'm like, oh, we need to change this fundamentally. I'm just going to drop the table and rebuild it because it's easier than trying to think about how to migrate this data. But so quickly, you get into a place where it's like, nope, sorry, can't do that have to treat this as realistic. So a bunch of the strategies that you're describing, like indexes concurrently, is one of the things that I'll reach for often because that allows me to decouple the timing there and not...again, the migration timeout that you're talking about is absolutely something that I want to have. Migration should go through quickly, and if they can't, then we need a different approach. Maybe we need to introduce the new column right to that one in parallel to the existing column, and then eventually do a switchover. It's definitely more work and involves a couple of deploys to get that done, but that's the unfortunate reality that we have to move to. I will say one of the things we talked about is like, if we hit that timeout, then we're going to stop that migration. This is a critical feature that I rely on deeply at Postgres, which is that schema migrations or DDL transformations; if I'm saying that correctly, I'm not sure I am, but throwing an acronym out there, it'll be fun. This is actually one feature of Postgres that I really rely on. My understanding is that Postgres has this; MySQL does not, but I may be off. I know that Postgres has transactional DDL transformation, so schema migration sort of things. I'm adding a column; I'm removing a column, et cetera. Those inherently happen within a transaction, and that's wonderful because if they do timeout, we want to be in a consistent state. The worst thing I can possibly imagine is being like, we got halfway through, but then we failed, or we lost connection, and so it's half migrated. It's like, oh God, I want to trust my database deeply. That's sort of one of the fundamental things that I have. And I've, over time, pushed more and more into the database and saying let's have check constraints. Let's have null true and all of these sorts of things so that the data in my database can be deeply trustworthy. The idea that a schema migration could go awry, and suddenly we've got like, well, half of the rows have these extra columns. What does that even mean? How do you live in that world? So I love this feature of Postgres. I really rely on it. I feel very bad whenever I have to disable it. I think there are some enum-related things that require disabling DDL transactions. And whenever I type that in a migration, I'm like, I don't like this. I'm not happy about this, but it's the world we live in for now. STEPH: If we're sharing our truths, yeah, adding an index concurrently also you have to remove that DDL transaction and disable it. For a previous project that I was working on, we often ran into that timeout where we'd run a migration, and then it would timeout. And we would then just specify and be like, "Hey, for this migration, I'm going to bump you up to a minute. I'm just going to make it longer." And that felt questionable at times, but I at least appreciate the explicitness of it where you're making that decision to say, nope, I think this is fine. It's not going to impact anybody, or we're going to run it in off-hours. I do want to extend this to a minute, and then make sure you do reset it, so it doesn't affect it globally from there on out. But that's something that you can do, and I have done before, which I feel is important. You still want to know some of your outs in case you do need something like that just to fix things in a moment but then at least be intentional for when you're using it and then communicate to the team like, "Hey, I'm doing this and let me know if you have concerns about it." For this specific scenario that Matt provided about we recently needed to delete a lot of old rows out of a large table, and the team had a lot of discussion about how to handle this without impacting production users; I happened to have a really nice conversation with Steve Polito, a fellow thoughtboter, about this particular question. And he had a very thoughtful response that I hadn't considered where he suggested starting with deleting the data for a small set of records. So, for example, if you're working with a users table, you could scope the data deletion to only inactive users and then use a feature flag to disable any interactions that would be affected by that data loss, run that change to delete the data for those inactive users, and then check for unexpected errors or side effects. So then that way, you have this moment to pause to say, "Hey, did we forget something? Is there something about this application that's still relying on that data that we forgot about? We've only done it for a small amount of users, so we're in a safer space." So then, at that point, you can either repeat those steps for another batch of records or use that feedback to then drop the column with confidence. And that was an approach that I hadn't considered, but I really liked that idea. CHRIS: Yeah, it's a nice, I'd say methodical approach to what can be a very complex and difficult to wrangle task. I will say I haven't actually explored this too much, but I've always had in the back of my mind, like, if we're deleting data from the application, ideally, we're saying this data is no longer needed. But I wonder if using table partitioning is an alternative that can be useful in these cases. What if we're able to figure out the correct partitioning? It's often time series sort of stuff. What if we're able to lean into that and say, "Let's partition this by year." And then yeah, we don't use the old data anymore, but it lives in a separate partition. And therefore, I think Postgres is able to do reasonable things with that. And again, like disk space, we can have a lot more storage on disk, but RAM is really going to be the constraining factor of how much of the index fits in memory. And again, I haven't pushed on this. But I think that's an alternative approach that can be really interesting. But if we do have time-series data, in particular, Postgres is wonderful. But it's not necessarily honed exactly to that use case. And so, there are a couple of tools that I've kept an eye on right now: ClickHouse, Timescale, and InfluxDB being the three of them. And I think most if not all of them are based on Postgres, but then they build on top of it. And they add some deeper understandings of time series data and how to optimize querying and storing, and all of that. And so, is that an alternative that allows us to still stay in this world but then have a different approach and alleviate some of the burdens that might come with this heavy data that we have? STEPH: Yeah, all those sound interesting. I haven't heard of some of those. This is why I love chatting with you. You always bring interesting perspectives that I had not considered before, like the partitioning. Just to clarify, partitioning the data is a way of keeping that data, but then it's not indexed. So that way, your system isn't spending as much time making sure that data is easily readable. But then that way, you don't actually delete it, so then it's there should you wish to be like, oh, I wish I hadn't gotten rid of that data. CHRIS: I think so. I'll be honest; I don't deeply understand it. But I think you basically can say given a giant projects table within your system; we actually may have that logically grouped by user sort of thing. And so we can shard and partition and say, there are ten different buckets of these. And if we optimize it well such that all of the things that are logically together actually live together on disk, then it allows Postgres to be much more efficient. Similarly, with time-series data, then you can say, use this sort of windowing where it's each month, we get a new bucket. And then it's much easier to query across just that bucket because it's already sort of partitioned down in that way. But I'll be honest; I'm now speaking well past my actual knowledge. I've never actually worked with it. But it's one of those things that I have in the back of my mind. Like if all of my other tools fail me and if I cannot solve these performance problems in a Postgres system with indexes, and tuning, and other things like that, then I will look to partitioning. So I look forward to that day when the data problems are so massive that I need to table partition. STEPH: Got it. Like they say, it's a good problem to have. While adding to the list of tools, there's one that I discovered recently; it's called Safe PG Migrations. And it's very similar to Strong Migrations, where Strong Migrations will warn you and say, "Hey, this is not safe. There are other ways to write this migration." Safe PG Migrations take some more aggressive approach and will rewrite your migration to be a safer version. And I don't know how I feel about it. I love it, and I hate it. [laughs] It's one of those the magic is there, and that could be phenomenal. But I get squeamish when things want to rewrite something as important as my migrations. But on the other hand, it is like a really nice default for the team because it's more than a warning. So that way, if you're trying to put something more strict in place for people to follow, then this would be a good way to do that. CHRIS: I'm very intrigued by that as a tool because if it were obvious, then Postgres would do it. The team behind Postgres does absolutely amazing work. And so if I tell them, "This is the change I want to make to the system," and they're like, "Cool, we're going to do that super inefficiently," and someone else is like, "No, no, no, I can trick it." Postgres is good at tricking itself, is my stance. So I'd be intrigued as to what secret knowledge they have or what are their caveats where Postgres has to handle every possible edge case. And therefore, it's slower because of pessimistic concerns that it has. But this tool says, "No, no, as long as you're not doing this very terrible thing, you're fine. And we'll rewrite it to a safer, faster version." But I'm just kind of intrigued, like, why do you think you're better than Postgres? STEPH: [laughs] Why do you think you're better? Well, I do you have an example I can provide. It's one that they have on their README. And this one highlights that if you're adding a column to an existing table and that you're adding a default value and no constraint, then they show you how it's rewritten where they set explicitly the lock timeout, and then they will add the column. And then they will set the default value but not in a way that it's going to do a table scan where it's going to add it for all the existing records; it's going to be for new records. And then they, let's see, they also update the users in batches to then set a default value, and then they will reset the statement timeout because it looks like they are...yeah, because initially, they change it, so they're resetting it to an original value. And then, they set the column Null constraint. I know I just said a lot of things reading from their README. But they have a good example here that kind of highlights that this is how they rewrite it. So I do find that more reassuring as long as I can then see how it was rewritten, and then I can validate it and confirm it with what I think is appropriate. Then I still have full control. Then it's more of a hey, we rewrote this thing for you. Feel free to review it and then change it as you see fit. As long as I have that final authority, then that makes me feel better about this. CHRIS: Got it. That makes sense. And the thing that you're describing, I think, is a semantically different thing than the first migration where it's like, do this thing. And they're like, well, okay, you could. But if instead, you did X, Y, and Z, then it would go way faster and be way easier. That makes a lot of sense. And it feels like shared knowledge wrapped up into a tool which I'm always a fan of that. STEPH: Yeah, in general, when I think about general strategies for schema changes, there are really three areas that come to mind or three strategies that come to mind. The first one is that we take incremental steps to avoid blocking reads and writes to the table, which then allows you to deploy during business hours or off business hours. That often means just more manual steps that you have to take to make sure that it's safe. And then the other one is scheduling downtime to run a migration. That is a very real option, something that you can do. Or have a fancy setup that utilizes followers for seamless migrations and upgrades. I feel like that's like the three big buckets that you can fit your strategy within. And it just depends on the needs of your application and users as to which one of those you're ready for or which strategy you need to use. What do you think? Are there any other big buckets that I left out of that list? CHRIS: No, I think we covered a bunch there. Hopefully, that was useful. Hopefully, it, I don't know, maybe introduced folks to some new ideas or ways to think about this sort of work. And yeah, with that, shall we wrap up? STEPH: Yeah, I've still got my Wordle to play for the day. So let's wrap up. CHRIS: The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. ALL: Byeeeeeeeeeee!!! ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.

The Bike Shed
324: Coding Time!

The Bike Shed

Play Episode Listen Later Feb 1, 2022 41:23


Chris updates us on his new window manager of choice, Moom, and tells us what's good with it. He's also giving yet another task manager a go: OmniFocus. (Sorry Things.) Steph talks about defining test classes in RSpec and readdresses flaky tests to improve CI build time. Chris is worried about productivity. He's still not coding as much as he'd like to be. Steph lends an ear, and together, they discuss potential ways Chris could gain back a little bit of coding time at work. This episode is brought to you by ScoutAPM (https://scoutapm.com/bikeshed). Give Scout a try for free today and Scout will donate $5 to the open source project of your choice when you deploy. Moom (https://apps.apple.com/us/app/moom/id419330170?mt=12) OmniFocus (https://apps.apple.com/us/app/omnifocus-3/id1346190318) Is It Worth the Time? (https://xkcd.com/1205/) Knapsack Pro (https://knapsackpro.com/) Shopify Monolith (https://shopify.engineering/shopify-monolith) Sacrificial Test Classes (https://blog.bitwrangler.com/2016/11/10/sacrificial-test-classes.html) rspecq (https://github.com/skroutz/rspecq) Become a Sponsor (https://thoughtbot.com/sponsorship) of The Bike Shed! Transcript: STEPH: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Steph Viccari. CHRIS: And I'm Chris Toomey. STEPH: And together, we're here to share a bit of what we've learned along the way. So hey, Chris, what's new in your world? CHRIS: What's new in my world? Well, hey, Steph. Oh, I have an update on a thing that I think I talked about a while back or at least asked on Twitter. But I've been looking for a window manager for forever. And in that way that I sort of overcorrected a while back, I think where I'm no longer allowed to do anything related to productivity or dev tools. I was just forbidden because it was a time sink. I'm slowly trying to correct back and be like, you know what? I regularly think about how it would be nice to have a better window manager. So previously, I had used Divvy, D-I-V-V-Y, which is fine. It did an okay job, but it just didn't have quite the level of control that I wanted, or maybe I didn't investigate it enough. But it felt like it was lacking. So I did a little bit of research. A bunch of people recommended different things. There was Spectacle; there was Rectangle. There was a whole bunch of other things that I'm forgetting now because I have settled on Moom, M-O-O-M. Those are fun words. STEPH: I feel like you keep bringing interesting words [laughs] because last time, it was Things where you're tracking all the things. And now we have Moom to track the space. All right. CHRIS: If this is my legacy as a podcaster, then I feel like I will have done well just, you know, weird sounds mostly that's what he's going for. But yes, I've been using Moom now for…[laughs] God, it's just ridiculous to say, but here we are. STEPH: [laughs] CHRIS: I've been using it. I've been enjoying it. In particular, the thing that I liked about it...a bunch of the other ones that I looked at were like, oh, we've got all these different configurations. And you can move things any which way, and you can have any number of hotkeys. And I was like, wait, wait, wait, say more right now. You want to take over my global namespace of hotkeys and just clutter it with 19 different things? You know that that is a limited space that I'm working with here. And so Moom, somewhat uniquely, at least in the ones that I experienced, was what I would describe as a modal window manager. So much like Vim is modal where you start out in normal mode, and you're moving around and you kind of bounce and search and all of that, and then you enter insert mode. And in insert mode, keys do different things. And then in command mode...it's got all these different modes. And so there are lots of different namespaces for hotkeys. It's one of the things that makes Vim so powerful. Moom is similar in that there's one global activation hotkey. And then, within that, I can have a whole namespace of hotkeys. So like M will put something in the middle of my screen now. F will put something full-screen. And I don't need to remember weird multikey combinations for that. There's just the one to get started, and then I've configured it such that the tab will bounce to a secondary display and sort of rotate through them. M and F and Q and P I've got it physically laid out on the keyboard. So it looks like my screen. Q being on the left side will push something to the left side, P to the right side. And I'm very happy with that. I don't need a lot out of this tool. I don't need very complex management or scripting or any of that, which are very nice features that exist in the other ones. But that combination, the one hotkey to rule them all, and then the sub hotkeys within it, and the ability to mostly move between the screens and then put stuff where I want it is great. I'm very happy. STEPH: I think I've figured it out. So Moom, I think it's a combination of move and zoom, and that's how they got Moom. CHRIS: You're probably right. STEPH: That does sound really nice. I'm a Spectacle fan. And I have enjoyed it and just stuck with it because I haven't felt a need to change from it. And it's really nice where I use my arrow keys for which direction I want to go. So that has been easy for me to recall. But that sounds really nice, all the things that you're describing with Moom. CHRIS: Does spectacle have the like, is it some Command Option Control and then left or right or up or down? Or is it you type something, and then you type left, right, up, down? STEPH: I have to actually touch my keyboard to answer that question because I have the muscle memory, which is an interesting thing that my muscles knows it, but my brain has to really think about it. So I think it's like the Option Command, and then yeah, then use the arrow keys. CHRIS: Gotcha. That's roughly what I had when I was using Divvy previously, but I found just enough of a limitation there. And so Moom has been great as another tool. But I think Spectacle has a lot more features in terms of scripting and other fancier stuff that you can do, which is both super intriguing and, again, sort of the thing that I'm not allowed to do. [laughs] So I went with, like, this tool seems fine and has the one feature that I really want. That said, you brought up Things, which is the to-do list app that I've been looking at. I've been using it for a week now. It's great. I'm enjoying having a more structured way to say, like, here's what I'm doing today. Here's what I'm doing tomorrow. It's been wonderful. But I'm already looking at OmniFocus as a better version. STEPH: [laughs] CHRIS: Because I think there's some stuff that I don't love, and yes, I can hear my own voice in the back of my head that's like, always chasing that next thing. But I haven't actually made the effort to switch over or even tried. I've used OmniFocus in the past. But anyway, I'll let you know if I do make additional moves there. STEPH: Yeah, I'm enjoying this journey. Keep me up to date on it. I've heard of OmniFocus, but I know nothing about it. But I feel like I've heard good things. So I like this journey you're going on where you just keep switching and trying new things. That's fun for me [laughs], and there's chasing productivity. So I'm into it; I'm here for it. CHRIS: If I just invest enough hours to save a handful of minutes down the road, then I will have...oh no, wait, that's not how this goes. There's, of course, an xkcd about this which we can include in the show notes. But I'm trying to be very intentional with it. I waited for many years before I allowed myself to reinvestigate the world of to-do lists. And I'm hopefully going to keep it to just a couple of weeks of nonsense and then back to a few years of stable. That's the dream. But yeah, that's some of the smaller things that are up in my world. I have another topic that I want to chat about. But I'd love to hear what's new in your world? STEPH: Yeah, I have some interesting bits that I can talk about with the project that I'm working on. But more concretely, I have something that's been on my mind that I don't think that I've talked about here on the show, but I think would be fun to talk about because I just happened to run into it this week while working on some code. And it's the idea of defining test classes in RSpec so as you are testing part of your code, but then you want to create just like a fake class, something that you can use as a substitute for real application code. And so it's a really nice way that then you can have this replica behavior, but then maybe it's just one particular method or some behavior that you need to use in the class but then doesn't actually go to the real code. That's wonderful. That's great. One thing that I've learned is that with RSpec is when you are introducing a test class, so let's say if you have your RSpec describe and then either a string or it's the name of a class, and then you have a block so do, and then within that block is where you write your test. If you create a temporary class, say, like I have my class test class, and then I have some behavior, that gets defined in the global namespace. It's not scoped to that particular RSpec example. And the reason for that it's not specific to RSpec. RSpec is not the one that's doing this; it's actually Ruby behavior. So for Ruby, when you're defining within a block like that, if you're defining a constant, if you're defining another class inside of a block, it's going to use the outer namespace as its namespace. So if you had a top-level class that you were defining, but if you define a class as a block, and then inside of that block you define a constant, that constant is then defined in the object namespace instead of within that particular class that you have written. And so that's why RSpec has this behavior. Because someone brought up a really great question about this on RSpec::Core asking about it, and they're like, yeah, that's actually how Ruby works. And so we're not going to change RSpec's behavior since that is how Ruby has decided to handle this. And the part where this becomes important is when you define a test class within an RSpec example. While it may be unlikely that someone is going to use that exact same name for their test class that they're going to create in their RSpec example, if they were to use that same name, then you're going to have a collision between the two. One of them's going to win, and you're probably going to end up with some really weird test failures because it's going to get confusing as to which class is being used, and they may not match up with each other. So one way around this, and this is going to be one of the rare times that I suggest this, but let. Let is scoped to an RSpec example. And so you could define a class inside of a let, and then that will scope it to the example. There are probably some other approaches as well, but that's the one that I'm most familiar with to ensure that when you define that class or constant, it's not getting defined in the global namespace and ensuring that none of the other tests have access to it. CHRIS: Well, this is certainly interesting. I'm pretty sure I've been operating under the opposite assumption for the entirety of my career. This is good to know. I feel like I probably have had tests that failed because of this. And then I learned this truth, and then I subsequently forgot it. I don't know if you know this, but if you define a method within just a helper method that you extract in RSpec, are those also on the global namespace? I don't define classes in RSpec blocks that often. It's pretty rare. Like if I have a controller concern sort of thing that I want to test, I might say random controller and inject the thing there or some other abstracted piece. That is the only case I can think of where I have a fake model or a fake controller or something like that for test purposes. But it doesn't come up that often. I do extract a heck ton of local helper methods. And I'm wondering now, are those all in the shared global namespace? STEPH: I'm pretty sure they're not. And I'm getting on the edges of my knowledge here, but I think it has to do with the fact of when you're defining a constant. So if you're defining a class versus an actual constant, that will get into the global namespace because it's using the outer scoping. But in my experience, I'm pretty sure that's not true for the method just because I remember one time I did some funky stuff with RSpec. And I remember seeing that I couldn't access those methods from another example. CHRIS: I like the honesty. And you're like, to be clear, I was doing something weird, but I learned that day. Okay, that's good because at least that part maps to my understanding. So methods may be safe, but classes get shared. Very interesting. STEPH: And it's something that I rarely think about or had worried about just because if I'm defining a fake test class, I often will put it somewhere that's intended to be more global. So I'll stuff it somewhere in like spec support. So then other people can see, hey, I've already mimicked this behavior. So if you need to use the same thing, just go ahead and use this. It's not often that I am adding that class directly to the RSpec example group. So I think I've been fortunate where I haven't actually run into that conflict for that reason. But this came up while giving an RSpec course. And while we were just in a very small, tiny codebase and replicating some examples, someone in the class was like, "Hey, by the way, do you know that that's in the global namespace?" And I was like, "No, friend. Tell me more." So thanks to that person, they're the ones that actually enlightened me about how it's going into that namespace and how it can actually pollute your testing namespace. There's a really good article that's written by Ken Mayer. And we'll be sure to include a link in the show notes that talks about it and also provides the let example as a way to work around this. And also links to the GitHub discussion on RSpec::Core, where they talk about this behavior and why things are the way that they are. Circling back to some of the more general project-y things that I alluded to earlier, I've shared a bit about the project that I'm working on. But just to recap it, it is focused on helping a very large team that has a large number of tests, around 85,000. And they are looking to address flaky tests that they have and overall really improve their CI build time. So right now, it takes about 30 minutes for the build to take place. But they also have flaky tests, and then that slows things down. And so, the re-verify rate has been painful for them. There's been some really great work that has improved that, particularly there is a, I think we've talked about this before, but where they're re-verifying certain flaky tests, which isn't great because they're still flaky tests, but at least they're not preventing people from moving forward and shipping code. But some of the bigger stuff that is just on my mind is when you have a very large team and a very large application, by large team, I'm talking about 100 developers, and they are all contributing to this codebase. And there are around 85,000 tests, and that has grown substantially in the last 12 months. And so, if you think about the trajectory of the addition of those tests, it is just going to continue to grow. So there's a concern there of even if we address flaky tests and we improve things, there's an architecture concern of how do we really reduce the CI build time? And so there's that aspect, and then there's also the aspect of then well, how do we still work to improve the tests and the codebase as well as we go across all of these disparate teams? And right now, there is a bit of a culture where engineers don't feel empowered where they can necessarily address all of the flaky tests or things that they run into. And so there is a bit of a mindset of I'm stuck on this, or this test failed, or it's flaky, or I don't understand it. So I'm just going mute it, or I'm going to hand it off to someone else to work on it. So there are three big areas that are on my mind. The first one is architecture. You can throw architecture at it. There's also the code quality that's a concern. And then how do you improve the code quality in a way that you're improving it fast enough that then you've got 100 other developers that are also contributing to it at the same time? And then individual IC empowerment where then people feel like, hey, I ran into a slow test or a flaky test, and I feel like I can triage this, and I can make changes. For the architecture piece, we're still in the infancy stages of how to approach this and the strategy that we're using. But one of the ideas that has come up is how do we reduce tentpoles? And the tentpole is like when you're running your test and, let's say that it's parallelized, all of the various tests. But there is one process that takes like 20 minutes, and then the other process is completed in 5 minutes as a drastic example. And overall, you could have reduced your time if you had managed to split that 120-minute process across all the other workers who are then available for that work. So there are some tentpoles that are taking place. And that could be one first step in reducing the CI build time. There are also discussions around how to scale horizontally. Right now, we don't think that's something we can do with the service that we're using to run the test. But it's something that maybe we need to manually look into is then how do we build a queue of all these tests and not where we just split test by a file, which is typically how the Parallelize gem does it. But you could actually split up tests within a file. So if you had a particularly large file, that doesn't necessarily matter. But then building a queue of all these tests so then as each test finishes, a worker can just grab that next test. And then also you can easily scale up and scale down workers. As I'm saying that, that feels big, that's a lot to invest in. But that as an idea is how can we essentially then scale the architecture? So even as we continue to invest in the tests, in the system, and they continue to grow, our architecture can keep up with it. CHRIS: That last bit there is super interesting to me. It's something that I've looked into and haven't pursued yet. We're currently running on CircleCI with our test suite. And I don't even know that we pushed on parallelization because we're early enough on that. And we turned off bcrypt recently, which super-duper helps with the speed up. But overall, the test suite time is fine, is where I would put it. It had crept up, though, to a place where it was starting to be painful, is how I would describe it. And I think it's very easy for that to just continue growing and suddenly, it's 20 and 25 minutes. And then, depending on your merge strategy and all of that, it can be all the more complicated, and this gets in the way of deploys. And so, I think it is a super important thing to keep an eye on. I know Charity Majors pushes really hard for 15 minutes from merge to deploy to production. And so if your CI suite takes 25 minutes, then already you're stuck. As an aside, I just once more want to say out into the ether, CircleCI or any other CI platform, if you would allow me to say yes, we've already tested this Git hash, this Git SHA, or the working tree, ideally, because that's also deterministic, I would love that feature. I would love to not have to rebuild the same code when it gets merged into main, just saying once more out into the world. Also, GitHub, if you want to put me on the merge queue beta, I would love that if anybody out there is listening. [laughs] STEPH: I like how this has become a special requests hotline for all the things [laughs] that you're hoping to get a part of or features you'd like to see added. CHRIS: Hello, internet. I have some requests. STEPH: [laughs] CHRIS: I would love to see those things, but in the world where those don't exist. The particular thing that you're talking sort of a test queue, is something that I've seen. So Knapsack is a...what's the word? It's a tool; it's a service. It's a combination of things. But it does that essentially where it starts up a local build agent. And then it basically says like, all right, give me all of the tests that you need to run, and then I will feed them back to each of the individual agents that there's one agent running per parallelized process. And so say you've got five of them. The first one says, "Hey, give me a test," and runs it. And the second one says, "Give me a test," and et cetera. And so, the queue manager on the other side is in charge of that orchestration. And it means that they basically all finish in identical time, with one being an outlier, whichever one happens to be the longest. But it's only going to be however long your longest test is is basically that outlier versus what you're describing of like, well, if we split it by file, we can end up with more naive things where there's a bunch of feature specs on one of them, and it skews by two minutes. We obviously don't want that. So Knapsack, in particular, is a tool that I've looked at, but generally, I'm very interested in that as a solution to how do we maximally take advantage of parallelization there? STEPH: Interesting. I have not heard of Knapsack. There is one that sounds similar. It's called RSpec Queue. And it does some really interesting work where it will split the individual test, so it won't do it by file. It will also look at historical data to then try to be intelligent about how it's going to split it and find the longer running test. And I believe it uses Redis to then keep track of the test set up in run and things that still need to be run. That is a gem that the team is looking into using as well. I don't know how that works if that can integrate with the current platform as we're using TeamCity to run tests. I don't know if that's something that can integrate with TeamCity, if it's a replacement. I don't have all of the knowledge about RSpec Queue yet. But it seems to do a number of the things that we're interested in. So even if we can't use the gem, then maybe it's something that we can still imitate. CHRIS: The other thing that I'm surprised we haven't said yet is this is one of the places where people would often reach for microservices. I feel like we have to have the microservice conversation at this moment. Microservices can actually be a great solution to organizational problems. As a team scales, it does become really hard to manage a large group of developers. And so microservices introduces a very fixed boundary that then draws nice lines that you can have around things. And so, the individual build time for a portion of your application can be much more manageable by virtue of that. But it has this huge cost of technical complexity and overhead and et cetera, et cetera, all of the reasons that we may not want to go that route. And so interestingly, I was just looking at Shopify's Deconstructing the Monolith blog post, which I think at this point, they've skewed a little bit more into the microservices. Shopify is huge, one of the largest Rails apps out there. And so looking at them and being like, oh, what are they doing? It's an interesting sort of plot a course and to see how long they waited before they even started thinking about the much deeper things and even exploring microservices. But in this blog post, they talk about a different approach where they stuck with sort of a monolith. But then they started to introduce Rails engines and clear encapsulation within the large codebase such that then you can actually start to say, well, we don't need to run all the tests every time because if we're making a change within this section of the application, then we just need to run those tests. I've also heard of organizations having some logic that can determine based on the code change; we know the associated test files that we should run. I'm scared of that is how I would describe it. I want to trust my test suite. I want to be able to deploy on a Friday and say if tests are green, it's going out to production. That's great. And I worry about that sort of thing. That's hard to get right. That feels like caching, right? And that's one of those things that we historically get wrong a lot. But nonetheless, that is an approach that large organizations I've heard having good success with. So some way to determine what's the affected code and what tests do we need to rerun and et cetera. And that can really drastically reduce down the scope of each CI build. But those are some larger things that I have not had to reach for on any of the applications I've worked with. I've taken different approaches, different ways to reduce the time or otherwise Parallelizer et cetera. But it's interesting for when you get to a certain scale. STEPH: Yeah, it's funny that you bring up that idea because that came up in conversation with some of the other developers as well, was the idea of, like, what if we could just not run all the tests? You changed one file, and you don't need to run everything. And I immediately was like, that sounds very cool and super hard to be able to get right. And a lot of this code is extremely coupled, which then moves to the code quality area. So I suspect a lot of the test times could be improved by creating smaller objects because right now, a lot of the tests will load the entire world because they have to. They have to test everything. And so that is creating a ton of data, and then taking a long time to run versus if we were able to split out that code into smaller objects and test in unit tests, then that would also help speed up. But that's also hard to do. Where do you look first? We do have some great data, thanks to RSpec. RSpec is letting us know how long each test file takes to run, and then we are capturing that data. So I can go look at which files and say, oh, this file takes 10 minutes to run. Let's look at that file first versus some of the other ones that are performing better. But that is a battle that will take a long time to win. And it's something that takes consistency and then also encouraging others to join that battle. So while it's very important, it doesn't address the concern of tests growing rapidly and then being able to support that. Something that you said in a previous episode also was on my mind in talking about building processes in a way that encouraged people that they can make small, quick changes. And I think that's really important. So if we can build out the architecture to help scale this so then the tests were running in say 15 minutes, then if someone saw a test and they wanted to make a small refactor, they saw a factory.create, and they're like, oh, that could be a FactoryBot.build_stubbed instead and issue that into a pull request or change request and get that merged. I don't know if people feel as comfortable doing that right now because it takes them 30 minutes or longer to run the test. But that idea of how do we get a structure in place where people can make tiny, little improvements and do that as a whole, as a team, to then work on the code quality concerns? CHRIS: That last little bit is so interesting where you're saying, like, oh, we have a FactoryBot.create, FactoryBot.Build, but it has the overhead of having to go through the 30-minute test suite. But coming back to the thing we were talking about before, what if we didn't have to run all the tests? Although I find it very hard to tell, given a code change in actual production code, what tests do I need to run? When I'm just changing a test, I'm pretty sure I know which test I need to run in order to determine if that test still runs correctly. So that feels is there an optimization that can happen there? Which is I've only made test changes; therefore only run the changed tests. And then that's an encouragement to say, like; this is a part of our codebase that we are trying to improve on. Let's optimize the iteration speed there. You'd have to figure out how to write that. And so it's probably much like my productivity adventures, maybe not a good investment. Although given that this is such an organizational concern, maybe that is the thing that's worth spending an afternoon on and seeing if it could happen. Because if you can speed that process up, get more [inaudible 23:46] and more iteration in fixing the tests, that feels like it could be a win. STEPH: I think that's a really good idea. I think we could certainly tell that if a file's changed, that it's only a test file that has changed. And then I've heard very good things from the other developers that TeamCity has a wonderful API to work with. And so there's a way that we could then tell TeamCity to say, hey,...or it may not even be a TeamCity command. It may just be somewhere in the universe we have to say, "Hey, RSpec, only run this test," or "TeamCity, we're only going to feed you this one RSpec test to run, so user agent but only run this particular test." So I really like that idea. I think that's really intriguing. And I'll bring it up with the team because that would be a huge win, especially as Joël and I are really focused more on tests. That would just improve our lives. So selfishly, I'm excited about that idea because we are touching less of the application code and more focused on improving the test at this point. CHRIS: I mean, if right now you're getting, say, 5 or 10 pull requests through a day which frankly feels like a high bar on this, if suddenly that's 10 to 20, that's material right there. STEPH: Yeah, I don't know how large of an impact it would have for the rest of the team because I don't know how often they're only making changes to a test file, but it still feels like a nice optimization to have. Cool. Well, thanks. I appreciate that idea. CHRIS: My pleasure. Mid-roll Ad And now a quick break to hear from today's sponsor, Scout APM. Scout APM is leading-edge application performance monitoring that's designed to help Rails developers quickly find and fix performance issues without having to deal with the headache or overhead of enterprise platform feature bloat. With a developer-centric UI and tracing logic that ties bottlenecks to source code, you can quickly pinpoint and resolve those performance abnormalities like N+1 queries, slow database queries, memory bloat, and much more. Scout's real-time alerting and weekly digest emails let you rest easy knowing Scout's on watch and resolving performance issues before your customers ever see them. Scout has also launched its new error monitoring feature add-on for Python applications. Now you can connect your error reporting and application monitoring data on one platform. See for yourself why developers call Scout their best friend and try our error monitoring and APM free for 14 days; no credit card needed. And as an added-on bonus for Bike Shed listeners, Scout will donate $5 to the open-source project of your choice when you deploy. Learn more at scoutapm.com/bikeshed. That's scoutapm.com/bikeshed. CHRIS: What else is going on in my world? I continue to not code a ton which is interesting and probably makes sense for right now. But to share a small anecdote from this week, we had retro, and I ended up attending retro ever so slightly late. I was doing a hiring interview, which is super exciting. Again, for anyone that's out there, we are hiring at Sagewell Financial. And I would love to chat with you if that sounds interesting. But so I was having a wonderful hiring conversation that ran a little bit long. So I was a little bit late to retro, and I arrived, say like eight minutes in, and someone was expressing a concern. And the concern was, I very sincerely know this to be true, but they were saying in the most positive way. But they were like, "It'd be great if Chris could code more," and not in the judgmental like, Chris, why are you not getting as much done? Not in that way at all, very much in the it would be great if Chris had more time, if there wasn't as much pulling my attention in different directions. But then it kind of went into this interesting direction. So we then go back through and address the concerns and talk as a group about how we resolve them. But this one was like, my name was in the concern, again, in a very positive way, in a very supportive way. And we had a wonderful conversation, and there were really great ideas that were passed around. But man, did I feel weird having my name in a retro item. [laughs] STEPH: So one thing I've learned is that you do a really good job when you are giving presentations and being in the spotlight. But I don't think you actually love it. You love sharing content and things that you have learned. But I could see how being a focal point, especially if there's a concern or something that could have a negative connotation, that would feel squeamish. It would make me feel squeamish. CHRIS: I hadn't thought about it in that way. But as you say it, also, this conversation is a meta version of that. Like, let's talk about me talking about me. I don't want to be the center of attention. But I love technology or process. I love talking about the work. That's great. And so I'm happy to do that. I'm happy to stand in front of a room and talk about it. But yeah, when it's about me, that's weird. And so now I'm going to move...well, no, I'm not going to move on [laughs] because this is the topic right now. But so there's a bunch of things that we have been trying to introduce. And I think this is a useful part of the conversation more broadly and less about me. So one of the things that I think I mentioned in a previous episode was the introduction of point-dev, which is each week, we rotate through a person. And that person is in charge of triaging the errors, making sure that nothing is stuck in Sidekiq, responding to any support requests, et cetera, et cetera. But they're meant to be the frontline such that everyone else can be heads down and really focus on the work. And what was interesting of the three developers that are working on the project, I am point-dev this week. So I was like, yes, that's awesome this week because I'm the person on the frontline. That has not helped me, but in the future, it will. And then one of the other developers mentioned that they feel like it's really useful but also feel like it's been noisy. And we realized the previous week was their week on point-dev. But the other developer was like, "Yeah, it's been great. I haven't had to think about anything." And so they have been off of that rotation for two weeks now. They'll be taking it over next week. But it is doing exactly its job of providing that attention coverage so that they can keep their focus on the code, and that's really wonderful. So I'll be honest, when we started talking about it, there was a tiny voice in my head that was like, is this a failure mode? Should we be dealing with the noise rather than having a process to address it in the moment? Should we be dealing with the root cause rather than the symptoms? And I still think that's a good point of view. But we found so much value from this. And as I've mentioned it, many people are like, oh yeah, we have that. It's great. I've heard enough positive things. So I've backed away from that. But there was a voice in my head that was like, are we failing right now? But yeah, so point-dev has been really wonderful. And next week, I will have to...well, frankly, the next two weeks, I'm off of point-dev appointments, so I'm very excited about that. I've been doing some of the product management or sort of the tech side of the product management and helping to triage cards and make sure that there's very clear work lined up for the engineering team when they're ready to do that. I'm trying to back away from that just a little bit. And one of the things that we did there was introduced an inbox column in our Trello board. You know how I love a good inbox. You know how I love to get to inbox zero. But that is a good way for me, for anyone now in the organization, which I don't want everyone to have to learn our processes, but just saying, "This is the place that you put requests, and we will deal with them. I assure you of that." It has been great because that means I don't need to be quite as responsive in Slack. I can just gently redirect people, "Hey, if you don't mind, please put this in Slack in the inbox column, and that'll be great." That thing, though, that gentle pushback in Slack is one of the things that I've struggled with. And this was one of the more personal aspects of the conversation that happened in retro was me being, like, if we're being honest, I tried to do that. But it's not my favorite thing to do in the world. Whenever someone asks me something, I want to be helpful. I don't want to seem rude or brisk or like I'm too busy for you, et cetera, et cetera. So I will often respond to the question or do the thing that they're asking and then say, "In the future, if you could go to this other place." And ideally, I'm slowly moving forward and being like, "No, no, no, please go to the other place. We've talked about this a few times." But it is an interesting example of one of the specific aspects of my personality coming through in this. But that introduction of an inbox has been great. Love me a good inbox, as I said. And then, more generally, we just tried to talk through what are the things that I'm doing? Do I need to own all of those uniquely? And some of them the answer we decided was yes but some of them we decided no. And we started to sort of distribute the work there or some of the meetings or different aspects of it. And so overall, it was a really great conversation but also very weird for me. STEPH: Yeah, because then you wonder, am I not doing the right thing? Am I not spending my time the right way? But then hopefully, that meeting helped reinforce that yes, you are spending your time the right way and that you're doing a lot of productive things. There are just too many productive things for you to do, and so you have to prioritize those aggressively. I like all the things that you just highlighted. There's one in particular, the last one that you mentioned about finding things that you can hand off to others. And I love that for a couple of reasons. It came up in a recent conversation that I was having with some other thoughtbot developers around when someone's on a project, typically someone just falls into being the point person. They just happen to be the person that the client talks to and ask questions and goes through the most. And that's something that is okay. But we want to make sure that that's not a bad thing, that everybody is treated equally, that everybody is given equal opportunities and room to grow. And so, in my mind, whenever someone is that point person, or you have fallen into that role, it is your job to then pull other people up. So if you have been given the responsibility of running a particular meeting each week, then go ahead and do it once or twice, so you can demo it and show it to someone else as to how you do this. But then tag somebody else and say, "Hey, I'm going to let you or ask you to run this next time." So then that person can experience it. They can demo their style, and then it continues on to have more people. So I really like that you are highlighting it's not just beneficial for you to then distribute those tasks, but it's empowering for everybody else on the team as well. I'm curious, so what was the final outcome? It sounds like there are some really good things in place, and you're transitioning, handing some things off. But I can't imagine that things have gotten...all of your priorities are still there. So do you think you'll actually code more, or what's the outcome for next week? CHRIS: Short term, maybe probably not, if we're being honest, but trending in that direction. So one of the things that's going on right now is hiring. That is just an activity that takes a lot of time. And I care a lot about doing that well, both for the organization and then for individuals on the other side. I want to be respectful of their time and communicate in reasonable timelines and not leave people without an answer or follow up or those sorts of things. It probably makes sense for that to sit with me as the starting contact. And then from there, folks that are continuing on in our hiring process they're going to talk to many other members of the team, and that won't just be me. But there are a lot of first conversations that I'm having. And so right now, my schedule has a bunch of that, which is fine and good. And that will hopefully, at some point, we'll hire some great people. And then we'll be on the other side of that. And that piece of the work that I have right now goes away. Some of the other outcomes that we named there were a couple of action items. And so I think those will help, but they're sort of we got to work towards that. One is transitioning a meeting, but it's a biweekly meeting. And I'm not going to just not attend the next one. So it'll be me and one of the other developers attending to transition ownership of that meeting moving forward. And then from there, so like, two weeks from now, I will not have that consideration on my calendar. And that's like one 30-minute block that I get back or, depending on how you think about it, one block that that 30-minute broke up. I do want to touch back just on something that you're saying there. I think you're being very kind to me in saying like, no, but you've got so many things, and so it's hard to do that. I think that's true, but that's kind of the work overall, and my version of that is one thing. But everyone sort of has, as a team, we have a version of like, how are we being most productive? Are we making sure we're doing the most important things? And so it was interesting in the moment, but I think it was a very good conversation. And I want to make sure that both we as a team and then me as an individual, wherever that happens to be the case, are open to these sort of constructive things. Like, frankly, to do the work to figure out how to get work off my plate that hasn't felt like the most important thing. It felt like close to the most important thing, but then there were all the other things that I had to do. So I wasn't doing the work to figure out how to not do the work. It is a complicated sentence that I just said. But this was a case where retro, I think, very usefully highlighted that this was a good thing for us collectively to put effort into such that we can be more productive moving forward. It happened to be slightly more focused on me rather than the entirety of the team. But broadly, that kind of thinking is why I'm a huge fan of retro. I think it's a great place to take a step back think about how we're doing the work rather than just being in the work day-to-day. STEPH: So if I'm internalizing what you said correctly, let me know if not, but it sounds like you're in one of those places, and I've witnessed this with other people and myself where someone is overwhelmed. They have a lot to do, and they're very focused in that grind and in that moment of doing all the things that they have to do. And it's very hard to then say, "I'm in the weeds right now. And then I also have to figure out how to get out of the weeds." And that's a very different skill and mental space to be able to do that. Because often, when you're just in that mode, all you can focus on is a bit on survival at that time. And then it may take other people to notice to say, "Hey, you're in the weeds. We need to figure out a way to help you not live there and to find ways to distribute some of the work." Does that sound like a fair assessment? Because I think I say all that because I've just seen people in that position. And then they think back, like, oh, I should have offloaded stuff earlier. And it's like, yeah, true, totally. And it often takes a retro or someone else coming to you and saying, "Hey, I've noticed...I looked at your calendar today; how can I help?" [laughs] CHRIS: I think that's probably the right calibration. And mostly, my emphasis was just I want to make sure that broadly, any team that I'm on has the space for this sort of conversation. And that thing that you're saying exactly that phrasing of like, "Hey, I saw your calendar. How are you doing? How's that going, though? Are you feeling okay? [laughs] You can't sleep and whatnot." That can be a really useful thing to have and to have organizational norms about what are our expectations of how many meetings someone should have in a week. And where do we start to think about different things? You did use the phrase overwhelmed. I want to say that I'm like 101% whelmed. So I'm just ever so slightly overwhelmed, but it is like I'm in the weeds. I need to figure out how to clear some of the weeds so that then I can get out of it. And it was a great conversation that came from that. STEPH: That's awesome. I'm glad you got a good team that, frankly, felt comfortable bringing it up, and then that you could lean on them for ways to talk about how you could code some more and talk about priorities and where you want to focus your time. CHRIS: It will be an interesting thing. As the team grows, I don't expect this to get easier. We talked about this a number of weeks back. And I think for a while; hopefully, we clear a little bit of dust here, and then I get back to being a little bit more on the code, and that's going to happen for a while. But as I think about the longer sort of the future of the company, this is something I'm going to have to revisit a handful of times. And it's a really interesting question that I'm still struggling with internally. And where do I want to be versus what will be needed and whatnot? So it'll be interesting to see how it evolves. But for now, I think I can gain back a little bit of coding time, a little bit of maker time versus manager time, as Paul Graham's essay goes. And yeah, I think that'll be good. STEPH: Yeah, I like how you're already looking forward to the fact that it will probably fluctuate because, yeah, right now, you are sort of paying a tax. You are building up to then where you can have more people on the team. And then that may give you back some of your time where then you can code because you can outsource some of the work to them. But then, as the team grows, so are other responsibilities. And traditionally, being in a CTO role and most CTOs I know will code here and there because they want to, and they enjoy it, but it is not their full-time job. So I think you're really wise to have already noticed that and start thinking about how that's going to trend in the future. And it sounds like you might need to figure out how to throw some architecture at it. So then you can scale horizontally, and then you can just have more time to do all the things. Yeah, that's right. [laughs] CHRIS: You're suggesting microservices, right? That's how my job becomes easy? STEPH: Yeah. Well, I'm thinking more like RSpec Queue, but we'll have RSpec Chris or some version of that. CHRIS: Chris Queue. STEPH: Chris Queue. [laughs] CHRIS: And then I just paralyze my human, and then it'll be great. STEPH: Yeah, that's always worked out well in the movies. Whenever somebody clones themselves, that goes super well. CHRIS: Multiplicity is a fantastic piece of cinema, and I stand by that. STEPH: I haven't seen it, but I feel like it doesn't end well for the main character. CHRIS: I feel like every time I mention a movie, you haven't seen it. I feel like we need to do a movie marathon at some point just to catch up so that we've got shared analogies. But yeah, it's a fun movie. It's fine. It turns out fine in the end. But there are some humorous adventures that happen in the middle. Cloning maybe [laughs] isn't the most direct option to solve productivity problems. STEPH: [laughs] Yeah, I think I've got Labyrinth, Hackers, and Multiplicity now on the watch list. And I appreciate the fact that you know that I'm not likely to watch them, although out of the three, Hackers will probably happen. CHRIS: All right, what if I were to get a bunch of Pop-Tarts, non-frosted? STEPH: Ooh. CHRIS: Does that change -- STEPH: Wait, are you going to send them to me? Because if you just have them, that's no good. [laughter] CHRIS: Eat Pop-Tarts on a video call and be like, "Look at this movie. It's great." [laughter] STEPH: All right, bribery definitely works for me. [laughs] CHRIS: Okay, so got it, noted. And based on the nature of the conversation that we have devolved into here, I think we've probably reached a good point. What do you think? Should we wrap up? STEPH: Let's wrap up. CHRIS: The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show. STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari. CHRIS: And I'm @christoomey. STEPH: Or you can reach us at hosts@bikeshed.fm via email. CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week. All: Byeeeeeeeeeee!!!!! Announcer: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.