The Bike Shed

thoughtbot
undefined
Mar 1, 2022 • 53min

328: Terrible Simplicity

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. 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 offers full stack visibility with 16 different monitoring products in a single platform. GitHub - alassek/activerecord-pg_enum: Integrate PostgreSQL's enumerated types with the Rails enum feature Feature #7792: Make symbols and strings the same thing - Ruby master - Ruby Issue Tracking System RailsConf 2016 - Turbolinks 5: I Can’t Believe It’s Not Native! by Sam Stephenson GitHub - hotwired/turbo-ios: iOS framework for making Turbo native apps Become a Sponsor 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.Sponsored By:New Relic: Services down? New Relic offers full stack visibility with 16 different monitoring products in a single platform.Scout: Scout APM is leading-edge application performance monitoring 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 performance abnormalities -- like N+1 queries, slow database queries, memory bloat, and 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 worldwide call Scout their best friend and try our error monitoring and APM free for 14-days, no credit card needed! And as an added bonus for Bikeshed listeners: Scout will donate $5 to the open-source project of your choice when you deploy. Learn more at scoutapm.com/bikeshed.Support The Bike Shed
undefined
Feb 22, 2022 • 43min

327: Estimate Crafting

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. 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 offers full stack visibility with 16 different monitoring products in a single platform. Newton Subscribe to Email Newsletters in Feedbin GitHub - Shopify/packwerk Sunsama TickTick: To-do List, Tasks, Calendar, Reminder Become a Sponsor 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.Sponsored By:New Relic: Services down? New Relic offers full stack visibility with 16 different monitoring products in a single platform.Scout: Scout APM is leading-edge application performance monitoring 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 performance abnormalities -- like N+1 queries, slow database queries, memory bloat, and 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 worldwide call Scout their best friend and try our error monitoring and APM free for 14-days, no credit card needed! And as an added bonus for Bikeshed listeners: Scout will donate $5 to the open-source project of your choice when you deploy. Learn more at scoutapm.com/bikeshed.Support The Bike Shed
undefined
Feb 15, 2022 • 41min

326: Dongle Life

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. 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 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 Factories Should be the Bare Minimum Mystery Guest GitHub - varvet/pundit: Minimal authorization through OO design and pure Ruby classes Become a Sponsor 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.Sponsored By:New Relic: Services down? New Relic offers full stack visibility with 16 different monitoring products in a single platform.Scout: Scout APM is leading-edge application performance monitoring 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 performance abnormalities -- like N+1 queries, slow database queries, memory bloat, and 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 worldwide call Scout their best friend and try our error monitoring and APM free for 14-days, no credit card needed! And as an added bonus for Bikeshed listeners: Scout will donate $5 to the open-source project of your choice when you deploy. Learn more at scoutapm.com/bikeshed.Support The Bike Shed
undefined
Feb 8, 2022 • 35min

325: Pranting

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. 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 offers full stack visibility with 16 different monitoring products in a single platform. ClickHouse Timescale InfluxDB ddl-partitioning Become a Sponsor 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 find_n_batches, 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.Sponsored By:Scout: Scout APM is leading-edge application performance monitoring 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 performance abnormalities -- like N+1 queries, slow database queries, memory bloat, and 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 worldwide call Scout their best friend and try our error monitoring and APM free for 14-days, no credit card needed! And as an added bonus for Bikeshed listeners: Scout will donate $5 to the open-source project of your choice when you deploy. Learn more at scoutapm.com/bikeshed.New Relic: Services down? New Relic offers full stack visibility with 16 different monitoring products in a single platform.Support The Bike Shed
undefined
Feb 1, 2022 • 41min

324: Coding Time!

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. Give Scout a try for free today and Scout will donate $5 to the open source project of your choice when you deploy. Moom OmniFocus Is It Worth the Time? Knapsack Pro Shopify Monolith Sacrificial Test Classes rspecq Become a Sponsor 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.Sponsored By:Scout: Scout APM is leading-edge application performance monitoring 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 performance abnormalities -- like N+1 queries, slow database queries, memory bloat, and 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 worldwide call Scout their best friend and try our error monitoring and APM free for 14-days, no credit card needed! And as an added bonus for Bikeshed listeners: Scout will donate $5 to the open-source project of your choice when you deploy. Learn more at scoutapm.com/bikeshed.Support The Bike Shed
undefined
Jan 25, 2022 • 46min

323: Doing Things

Steph talks about winter storms and thoughts on name pronunciation features. Chris talks about writing a query to add a new display of data in an admin panel and making a guest appearance on the Svelte Radio Podcast. Finally, Chris decided that his productivity to-do list system was failing him. So he's on the search now for something new. He asks Steph what she uses and if she's happy with it. How do you, dear Listener, keep track of all your stuff in the world? This episode is brought to you by ScoutAPM. Give Scout a try for free today and Scout will donate $5 to the open source project of your choice when you deploy. Upcase advanced Active Record Svelte Radio Things Todoist MeetingBar SavvyCal Become a Sponsor 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. We have Winter Storm Izzy headed our way. It's arriving in South Carolina early tomorrow morning. So that's kind of exciting just because it's South Carolina. We rarely see snow. In fact, I looked it up because I was curious because I've seen it every now and then. But I looked up the greatest cumulative snowfall in 1 season, and it was 19 inches in the winter of 1971. I was trying to add an old-timey voice there. I don't know if I was successful. CHRIS: Does 1971 deserve a full old-timey voice? STEPH: Apparently. CHRIS: I feel like people from 1971 would be like, "We were just people in the 70s." Like, what do you... STEPH: [laughs] CHRIS: Wait. Nineteen inches, is that what you said? STEPH: 19 inches. That was total for the season. CHRIS: Yeah, we can bang that out in an afternoon up here in the North. So yeah, okay. You were here for the terrible, terrible winter, right? STEPH: Oh, Snowmageddon? Yes. CHRIS: Yeah, that was something, oof. STEPH: I don't remember how many inches. Was it like 100 inches in a month or something wild like that? I've forgotten the facts. CHRIS: I, too forget the facts. I remember the anecdotal piece of data, the anecdata as it were where we shoveled our driveway, and then another storm came, we shoveled our driveway. And then finally, I was living in an apartment, and it was time to shovel the driveway again. But the pile of snow on the lawn was too big. So we had to shovel the pile of snow further up the lawn to make room for the snow that we were shoveling out of the driveway. But I also remember that being a really nice bonding moment, and I met more of the people living in the...it was a house that had been converted into six apartments. So I actually met some of the people from the house for the first time. And then we hung out a little bit more in the day. So I actually have weirdly fond memories of that time. But to be clear, that was too much snow. I will officially go on record saying too much snow. No, thank you again. STEPH: It was a lot of snow. I think it broke Boston for a while. I remember I don't think I went to...I worked remotely for two weeks because they were just like, "Yeah, don't even try to come into the office. Don't worry about it." So it felt like my first dabbling into understanding quarantine [laughs] except at least with less complicated reasons, just with lots of snow. We also went snowboarding in Charlestown, where we were living. And that was fun because there are some really great hills, and there was so much snow that that was delightful. But I'm not expecting Snowmageddon in South Carolina, although people may act like it and rush out and get their milk and bread. But hopefully, we'll get a couple of inches because that'll be lovely. I don't know that Utah has ever seen the snow. So this will be fun. CHRIS: Oh, that'll definitely be fun. I imagine you've got like even if you do get some amount of accumulation, a day later the sun will just be like, "I'm back. I got this," and clear it up, and you won't have any lingering. The year of Snowmageddon, if I remember correctly, the final pile of snow left in July, the shared one that the city had collected. So you'll probably do better than that turnaround time. [laughs] STEPH: Yeah, it's perfect. It's very ephemeral. It snows, it's beautiful. It's there for a couple of hours, and then poof, it's gone. And then you're back to probably 70-degree weather typically what’s here, [laughs] which I have no complaints. There's a reason that I like living here. But in some other news, I have something that I'm really excited about that I want to share. So there's something that you and I work really hard to do correctly, and it's pronouncing someone's name. So whenever there is either a guest on the show, or we are referencing someone, we will often pause, and then we will look for videos. We'll look for an audio clip, something where that person says their name. And then we will do our best to then say it correctly. Although I probably put a Southern twang on a lot of people's names, so sorry about that. But that's really important to say someone's name correctly. And one of thoughtbot's projects is called Hub, which is something that we use internally for all of our project staffing and then also for profiles and team information; there’s a new feature that Matheus Richard, another thoughtboter, implemented that I am just so excited about. And now that I have it, I just think I don't know how I lived without this. And I want it everywhere. So Matheus has added the feature where you can upload an audio file with your name pronunciation. So you can go to someone's profile, and you can click on the little audio button and hear them pronounce their name. And then a number of people have taken it a bit further where they will provide, say, the American or English pronunciation of their name. And then they will provide their specific pronunciation; maybe it's Greek, maybe it's Spanish, and it's just phenomenal. And I love it so much. And I can't wait for just more platforms to have something like this. So really big shout out to Matheus Richard for that phenomenal feature. CHRIS: Oh, that is awesome. Yeah, we definitely do pause pretty regularly to go scan through YouTube or try and find an example. And often, people just start into talks, or they'll only say their first name. We're like, oh, okay, keep searching, keep searching. We'll find it. And apologies to anyone whose name we still got wrong regardless of our efforts. But it's making this a paramount idea similar to people putting their pronouns in their name. Like, okay, this is a thing that we should get into the habit of because the easier we make this, the more common that we make this. And names absolutely matter, and getting the pronunciation right really matters. And especially if it can be an easier thing, that's really wonderful. I hope Twitter and other platforms just adopt this; just take this entirely and make it easy because it should be. STEPH: That's what I was thinking; if Twitter had this, and then I was thinking if Slack had this, that would be a wonderful place to be able to just see someone's profile because we can see lots of other helpful context about them. So yeah, it's wonderful. I want to hear more people how they pronounce their names. Because I'll always ask somebody, but it would just be really nice to then be able to revisit or check-in before you talk to that person, and then you can just say their name. That would be delightful. CHRIS: I do feel like creating it for my name would be interesting. I actually had someone this week say my name and then say, "Oh, is that how you pronounce it?" And I stopped for a minute, and I was like, "Yes. I'm really intrigued what other options you were considering, though. I would like to spend a minute and just...because I always thought there was really only the one approach, but I would love to know. Let's just explore the space here," but yes. STEPH: [laughs] You ask them, "What else you got? What other variations can I hear?" CHRIS: [laughs] I would like three variations on my desk by tomorrow so that I can understand what I'm missing out on, frankly. There's a theme or an idea that I've seen bouncing around on Twitter now of people saying, "Yeah, I really just want to apply, get hired, work for one day, make this one change to a platform, and immediately put in my resignation." And I could see this like, "All right, I'm just going to go. I'm going to get hired by Twitter. This is it. This is all I'm doing," which really trivializes the amount of effort that would go into it for a platform like Twitter. I can't even imagine what engineering looks like in Twitter and how all the pieces come together. I'm imagining some amount of microservices there, and that's just my guess. But yeah, that idea of just like, this is my drive-by feature. I show up; I work for a week, I quit. And there we go; now we have it. STEPH: Well, we are consultants. Maybe we'll get hired for all these different companies, and that will be our drive-by feature. We'll add it to their boards and be like, "Don't you want this? Don't you need this?" And then they'll say, "Yes." [chuckles] CHRIS: I am intrigued because I can't imagine this hasn't come up in conversations at Twitter. And so, what are the trade-off considerations that they're making, or what are the reasons not to do this? I don't have any good answers there. I'm just asking the question because, for an organization their size, someone must have had this idea. Yeah, I wonder. STEPH: Yeah, there's; also, I'm sure malicious things that then you have to consider as to then how people...because, at the end of the day, it's just an audio file. So it could be anything that you want it to be. So it starts to get complicated when you think about ways that people could abuse a feature. On that peppy note, what's going on in your world? CHRIS: I had a fun bit of coding that I got to do recently, which, more and more, my days don't involve as much coding. And so when I have a little bit of time, especially for a nice, self-contained little piece of code that I get to write, that's enjoyable. And so I was writing a query. I wanted to add a new display of data in our admin panel. And I was trying to write a query, and I got to build a nice query object in Ruby, which I always enjoy. That's not a real thing, just in case anyone's hearing that and thinking like, wait, what's a query object? Just a class that takes in a relation and returns relation but encapsulates more complex query logic. It's one of my favorite types of ways to extract logic from ActiveRecord models, that sort of thing. So I was building this query object, and specifically, what I wanted to do here is I'm going to simplify down the data model. And I'm going to say that we have users and reservations in the system. This may sound familiar to you, Steph, as your go-to example [laughs] from the past. We have users, and we have reservations in the system. So a user has many reservations. And reservations can be they have a timestamp or maybe an enum column. But basically, they have the idea of potentially being upcoming, so in the future. And so what I wanted to do was I wanted to find all users in the system who have less than two upcoming reservations. Now, the critical detail here is that zero is a number less than two. So I wanted to know any users that have no upcoming reservations or one upcoming reservation. Those were the two like, technically, that's it. But say it was even less than three, that's fine as well. But I need to account for zero. And so I rolled up my sleeves, started writing the query, and ActiveRecord has some really nice features for this where I can merge different scopes that are on the reservation.upcoming is a scope that I have on that model that determines if a reservation is upcoming because maybe there's more complex logic there. So that's encapsulated over there. But what I tried initially was users.leftjoinsreservations .groupbyusers.id havingcountofreservations. So that was what I got to. And thankfully, I wrote a bunch of tests for this, which is one of the wonderful things about extracting the query object. It was very easy to isolate this thing: write a bunch of tests that execute it with given data. And interestingly, I found that it worked properly for users with a bunch of upcoming reservations. They were not returned by the query objects which they shouldn't, and users with one upcoming reservation. But users with zero upcoming reservations were being filtered out. And that was a surprise. STEPH: Is it because the way you were joining and looking where the reservation had to match to a user, so you weren't getting where users didn't have a reservation? CHRIS: It was related to that. So there's a subtlety to LEFT JOINS. So a JOIN is going to say like, users and reservations. But in that case, if there is a user without reservations, I know they're going to be filtered out of this query. So it's like, oh, I know what to do. LEFT JOINS, I got this. So LEFT JOINS says, "Give me all of the users and then in the query space that I'm building up here, join them to their reservations." So even a user with no reservations is now part of the recordset that is being considered for this query. But when I added the filter of reservations.upcoming, I tried to merge that in using ActiveRecord's .merge syntax on a query or on a relation, as it were. That would not work because it turns out when you're using the LEFT JOINS...and as I'm saying this, I'm going to start saying, like, here's definitively what's true. I probably still don't entirely understand this, but trying to do the WHERE clause on the outer query did not work. And I had to move that filtering logic into the LEFT JOINS. So the definition of the JOINS was now I had to actually handwrite that portion of the SQL and say, LEFT OUTER JOIN users on and then, you know, the users.id=reservations.userid and reservations. whatever the logic there for an upcoming reservation. So reservations.completed is null or reservations.date>date.current or whatever logic there. But I had to include that logic in the definition of the LEFT OUTER JOIN, which is not a thing that I think I've done before. So it was part of the definition of the JOIN rather than part of the larger query that we were operating on. STEPH: Yeah, that's interesting. I don't think I would have caught that myself. And luckily, you had the test to then point out to you. CHRIS: Yeah, definitely the tests made me feel much more confident when I eventually narrowed down and started to understand it and was able to make the change in the code. I was also quite happy with the way I was able to structure it. So, suddenly, I had to handwrite a little bit of SQL. And what was nice is many, many, many years ago, I recorded a wonderful course on Upcase with Joe Ferris, CTO of thoughtbot, on Advanced ActiveRecord Querying. And I'm still years later digesting everything that Joe said in that course. It's really an amazing piece of content. But one of the things that I learned is Joe shows a bunch of examples throughout that course of ways that where you need to, you can drop down to raw SQL within an ActiveRecord relation. But you don't need to completely throw it out and write the entire query by hand. You can just say, in this case, all I had to handwrite was the JOINS logic for that LEFT JOINS. But the rest of it was still using normal ActiveRecord query logic. And the .having was scoped on its own, and all of those sort of things. So it was a nice balance of still staying mostly within the ActiveRecord query Builder syntax and then dropping down to a lower level where I needed it. STEPH: I love that you mentioned that video because I have seen it, and it is so good. In fact, I now want to go back and rewatch it since you've mentioned it just because I remember I always learn something every time that I do watch it. On a side note, the way that you represented and described query objects was so lovely. I know you, and I have talked about query objects before because we adore them. But I feel like you just gave a really good mini class and overview of like, this is what a query object is, and this is what it does. And this is why they're great because you can test them. CHRIS: Cool. I'm going to be honest; I have no idea what I said. But I'm glad it was good. [laughs] STEPH: It was. It was really good. If anyone has questions about query objects, that'll be a good reference. CHRIS: Well, thank you so much for the kind words there. And for the ActiveRecord querying trail, really, I was just along for the ride on that one, to be clear. I did write a bunch of notes after the fact, which I've found incredibly useful because the videos are great. But having the notes to be able to reference...past me spent a lot of time trying really hard to understand what Joe had said so that I could write it down. And I'm very glad that I invested that time and effort so that I can revisit it more easily. But yeah, that was just a fun little bit of code that I got to write and a new thing that I've learned in the world of SQL, which is one of those topics that every little investment of effort I find to be really valuable. The more comfortable I feel, the more that I can express in SQL. It's one of those investments that I'm like, yep, glad I did that. Whereas there are other things like, yeah, I learned years ago how to do X. I've completely forgotten it. It's gone from my head. I'm never going to use it again, or the world has changed. But SQL is one of those topics where I appreciate all of the investment I've put in and always find it valuable to invest a bit more in my knowledge there. STEPH: Yeah, absolutely same. Just to troll Regexs for a little bit, they're powerful, but they're the thing that I will never commit to learning. I refuse to do it. [laughs] I will always look it up when I need to. But Postgres or SQL, on the other hand, is always incredibly valuable. And I'm always happy to learn something new and invest in that area of my skills. CHRIS: Yep, SQL and Postgres are great things. But let's see. In other news, actually, I had the pleasure of joining the Svelte Radio Podcast for an episode this week. They invited me on as a guest. And we got to chat about Svelte, and then I accidentally took the conversation in the direction of inertia as I always do. And then I talked a little bit more about Sagewell, the company that I'm building, and all sorts of things in the world. But that was really fun, and I really enjoyed that. And I believe it will be live by the time this episode goes live. So we will certainly include a link to that episode in our show notes here. STEPH: That's awesome. I haven't listened to the Svelte Podcast before. So I'm excited to hear your episode and all the good things that you said on it. I'm also just less familiar with them. Who runs the Svelte Podcast, and what's the name of the show? CHRIS: The show is called Svelte Radio. It's hosted by Antony, Shawn, and Kevin, who are three Svelters from the community. Svelte is a really interesting group where the Svelte society is, as far as I can tell, a community organization that is seemingly well-supported by the core team and embraced as the natural center point of the community. And then Svelte Radio is an extension of that. And it's a wonderful podcast. Each week, they talk about various things. So there are news episodes, and then they have guests on from time to time. Recently, having Rich Harris on to talk about the future of Svelte, Rich Harris being the creator of Svelte. Interestingly, if you search for Svelte Radio, they are the second Google result because the first Google result is the tutorial docs on how to use Svelte with radio buttons. But then the second one is Svelte Radio, the podcast, [laughs], which is an interesting thing. Good on Svelte's documentation for having such strong SEO. STEPH: I was just thinking there's something delightful about that where the first hit is for documentation that's a very helpful; here’s how you use this. That's kind of lovely. Well, that's really cool. I'm really looking forward to hearing more about Svelte and listening to you be on the show. CHRIS: Yeah, they actually had some very kind things to say about The Bike Shed and, frankly, you as well and our co-hosting that we do here. So that was always nice to hear. STEPH: That's very kind of them. And it never fails to amaze me how nice podcasters are. Everyone that I've met in this community that's a fellow podcaster they're just all such wonderful, nice, kind people, and I just appreciate the heck out of them. CHRIS: Yeah, podcasts are great. The internet is doing its job; that’s my strong belief there. But let's see. In other news, I actually have more of a question here, sort of a question and an observation. My work has started to take a slightly different shape than it has historically. Often, I'm a developer working on a team, picking up something off the top of the Trello board or whatever we're using for project management, working on that thing, pushing it through to acceptance. But all of the work or the vast majority of the work is encapsulated in this one shared planning context. But now, enough of my work is starting to spill out in different directions. Like right now, I'm pushing on hiring. That's a task that largely lives with me that doesn't live on the shared Trello board. Certainly, the rest of the team will be involved at some point. But for now, there's that that's really mine. And there are other pieces of work that are starting to take that shape. So I recognize, or at least I decided that my productivity to-do lists system was failing me. So I'm on the search now for something new, but I'm intrigued. What do you use? Are you happy with what you have for to-do lists? How do you keep track of stuff in the world? STEPH: Oh goodness. I'm now going to overanalyze everything that I do and how I keep track of the things that I do. [chuckles] So currently, I have two things that I used to track, and that is...okay, I'm going to expand. I have three to-do lists that I use to track. [laughs] Todoist is where I add most things of where whatever I just think of, and I want to capture it Todoist is usually where it goes. Because then it's very easy for me to then go back to that list and prioritize or just simply delete stuff. If I haven't gotten to it in a while, I'm like, fine, let it go. Move on. And then the other place I've started using just because it's been helpful in terms of linking to stuff is Basecamp. So we use Basecamp at thoughtbot, and we use it for a number of internal projects. But I have created my own project thanks to some advice from Mike Burns, a fellow thoughtboter, because he created his own and uses that to manage a lot of his to-dos and tasks that he has. And then that way, it's already one-stop shopping since you're in Basecamp a lot throughout the day or at least where you're going to visit some of the tasks that you need to work on. So that has been helpful just because it's very simple and easy to reference. And then calendar, I just live by my calendar. So if something is of the utmost importance...I realize I'm going in this in terms of order of importance. If something is critical, it's on my calendar. That's where it goes. Because I know I have not only put it somewhere that I am guaranteed to see it, but I have carved out time for it too. That's my three-tier system. [laughs] CHRIS: I like it. That sounds great, not overly complicated but plenty going on there. And it sounds like it's working for you, sounds like you're happy with that. STEPH: It has worked really well. I'm still evaluating the Basecamp, but so far, it has been helpful. It does help me separate between fun to-do items which go in Todoist and maybe just some other work stuff. But if it's really work-focused, then it's going in Basecamp right now. So there's a little helpful separation there between what's going on in my life versus then things I need to prioritize for work. What are the things that you're currently using, and where are you feeling they're falling down or not being as helpful as you'd like them to be? CHRIS: My current exploration, I'm starting to look for a new to-do list-type things. Specifically, I've been using Trello for a long time for probably a couple of years now. And that was a purposeful choice to move away from some of the more structured systems because I found they weren't providing as much value. I was constantly bouncing between different clients and moving into different systems. And so much of the work was centrally organized there that the little bit of stuff that I had personally to keep track of was easy enough to manage within a Trello board. And then slowly, my Trello board morphed into like 10 Trello boards for different topics. So I have one that's like this is research. These are things that I want to look into. And so I can have sort of a structure and prioritization within that context in my world. And then there's one for fitness and one for cooking. I'm trying to think which else...experiments, as I'm thinking about I want to try this new thing in the world. I have a board for that. So I have a bunch of those that allow me to keep things that aren't as actionable, that are more sort of explorations. But then they each have their own structure. And that I found to be really useful and I think I'll hold on to. But my core to-do board has started failing me, has started being just not quite enough. And then, more so, I wanted a distinct thing for work for a professional context. So I was like, all right, let me go back to the drawing board and see what's out there. And I did a quick scan of Todoist and Things, respectively. And I've settled on Things for right now. It just matches a little bit more to my mental model. Todoist really pushes on the idea of due dates or dates as a singular idea associated with most things. Almost everything should have a date. And I kind of philosophically disagree with that. Whereas Things has this interesting idea of there is the idea of a due date, but it's de-emphasized in their UI because not everything has a due date; most things don't. But Things has a separate idea of a scheduled date or an intent date. Like yeah, I think I'll work on that on Wednesday. It's not due on Wednesday; that's just when I want to work on it. It can have a separate due date. Like, maybe it's due Friday. STEPH: Is the name of the application that you're saying is it Things? Is that the name of it? CHRIS: Yeah, it is. STEPH: I haven't heard this one. You kept saying Things. I was like, wait, is he being vague? But I realized you're being specific. [laughs] CHRIS: It's one of the few things that...yeah, one of the few things that I think is not great about Things. It's from a company Cultured Code, and the application is called Things. And that is all I will say on that topic. Different names maybe would have been better, but they seem to have carved out enough of an attention space. Enough people know of it that if you search for Things and to-do list, it will very quickly pop up. But yeah, that's a pretty ambiguous name. They maybe could have done a different one there. But the design of the application is really nice. It's on my desktop. And now I have it on my phone as well, and they sync between them and all the stuff. So there's never going to be a perfect system. I'm certain of that. I've at least talked myself out of trying to build my own because, man, have I fallen into that trap before. Oh goodness, so many times. STEPH: I'm very proud of you. CHRIS: Thank you. I'm trying. STEPH: But yeah, it'll be interesting to see how it evolves. I continue to struggle with there are these things that come to mind, and I want to capture them during the day. But some of them are just stories I'm telling myself, which would probably be best captured in a journal tool. And then there are notes that I might want to keep on remote work and how people think about that. And so I'm starting to think about Obsidian or a note-taking system for that. And then I've got this Trello board concoction. And now I've got a to-do...and suddenly I'm like, well, that's too many things. And so I'm trying to not overthink it. I'm trying to not underthink it. I'm trying to just find that perfect amount of thinking. That's what I'm aiming for. I'm not sure I'm going to hit it directly, [laughs], but that's what I'm aiming for. 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. STEPH: Some of the topics that you mentioned earlier did stand out to me when you're talking about recipes and working out some other topics. Those are things for me that I often just put in notes. So I liked the word that you used for stories that you're telling yourself or things that you're interested in. Is that something that...I don't put it in Todoist or put it somewhere because I don't really have an action item. It's more like, yeah, this recipe looks awesome and one day...so I'm going to stash it somewhere so I can find it. I'm currently using Notion. I used Bear before. It is beautiful. I really liked Bear, but I needed a little bit more structure, and Notion gave me that structure. And so I will just dump it in Notion. And then it's very searchable, so I can always find whatever recipe or whatever thought that was as long as I try to add buzzwords to my own notes. Like, what would have Stephanie searched for looking for this? So I will try to include some of those words just so I can easily find it. CHRIS: I love you're defining yourself as a Stephanie. For a random Stephanie walking through the woods, what search terms? How can I SEO arbitrage a Stephanie? STEPH: What would she look for? CHRIS: Who knows? STEPH: That Stephanie, she's sneaky. You never know. CHRIS: You never can tell. Obsidian is the one that I'm looking at now. But I'm currently using Apple Notes. And it's really nice to be able to search directly into a note very quickly. I have that both via Alfred and then on my phone. And I'm finding a lot of utility in that, particularly for notes, for things I want to talk to someone about. But now there are seven different things, and how are they connected? And where is something? And to the question of where would a future Christopher look for this, let's make sure I put it in that place. But I don't know what that dude's going to be up to. He's a weird guy. He might look in a completely random place. So I'm trying to outsmart him, and oof, good luck, me. STEPH: [laughs] I have heard of Obsidian, but I don't recall much about it. So I'd have to look into it. I do feel your pain around Todoist and where it really encourages you to set a date. Because there are often things where I'm like, I saw something I want to read. And I know there are tons of tools. There are so many tools and videos and things that people could watch if they really want to invest in this workflow. But right now, I've told myself no, and so I use Todoist. And I see something I want to read, and so I just link to it. And I don't have a particular date that I want to read it. I'm like, this looks cool, and so then I add it to a reading list. But that also, I guess, could be something for notes. More and more, I'm trying to shove things into notes, so it feels less like a task and more of a I'm curious, or I'm interested in things that have piqued my interest. Let me go back and look at that list to see if there's something I want to pull from today or I need inspiration. That's what my notes often are; they're typically inspiration for something that I have seen and really liked, or maybe it's a bug that I looked into, and I want to recall how that happened or what was the process. But yeah, my notes are typically a source of inspiration. So I try to dump most things in there. I don't know if that's particularly helpful for your task, though, because it sounds like you're looking for a way to manage the things that you actually need to do versus just capturing all of your thoughts. CHRIS: Honestly, part of it is having a good system for those like, oh, I'd like to read this sometime. Ideally, for me, that doesn't go into my whatever to-do list system. But if my brain doesn't trust that I'll ever read it or if I feel like I'm putting it into a black hole, then my brain is just like, hey, you should really read that thing. Are you thinking about that? You should think about that and just brings it up. And so having a system externalized that I trust such that then the to-do list can be as focused as possible. It's a sort of an arms race back and forth battle type thing of like, I've definitely done the loop of like, all right, I want to capture everything. I want to have perfect, lossless, productivity system, and that is not possible. And so then I overcorrect back the other way. I'm like, whatever, nothing matters. I'll just let everything fall away. And then I'm like, well, then my brain tries to remind me of stuff or tries to remember more. And there's a book, Getting Things Done, which is one of the more common things recommended in the productivity world. And that informs a bunch of my thinking around this, the idea of capturing everything that's in your head so that you can get it out of your head. And in the moment, be focused and in the moment and not having to try and remember. And so that's the ideal that I'm searching for. But it's difficult to build that and make that work. STEPH: It seems the answer is there's no perfect system. It's always finding what works for you. And I feel like it's always going to change from hopefully not month to month because that would be tedious. But it may change year to year depending on how you're prioritizing things and the types of things that you need to remember or that you need to accumulate somewhere. So I feel like it's always this evolving, iterative process of changing where we're storing this. But I feel like where you store the notes and inspiration, that's something that, ideally, you want to make sure that you can always continue to keep forward. So even if you do change systems, that's something that's usually on my mind. It's like, well, if I use this system to store all of my thoughts, what if I want to move to something else? How stuck am I to this particular platform? And can I still have ownership of the things that I have added here? But overall, yeah, I'd be intrigued to see what other people think if they have a particular system that works for them, or they have suggestions. But overall, it seems to be whatever caters best to your personality and your workflow. That's why there are so many of these. There are so many thoughts, so many videos, so many styles. CHRIS: Yeah, I think a critical part of what you just said that feels very true to me is this is something that will change over time as well. Life comes in seasons, and my work may look a certain way, or my life may look a certain way, and then next year, it may be wildly different. And so, finding something that is good enough for right now and then moving forward with that and being open to revisiting it. And yeah, that feels true. So I'm in an explore phase right now. I'll report back if I have any major breakthroughs. But yeah, we'll see how it goes. STEPH: I will say I think the main tool that I have really leaned into, while some of the others will change over time, is my calendar. There are certain things I've let go. My inbox is always going to be messy. My to-do list is always going to be messy. But my calendar that is where things really go to make sure that they happen. And I will even add tasks there as well. So I feel like the calendar will always stick with me because I can trust that as the one source of like, these are the things that have to happen. Everything else I can check for during that day or figure it out as I go. Or if something gets dropped or bounces to the next day, it's okay. CHRIS: Yeah, the calendar is definitely a core truth in my world. Whatever the calendar says, that is true. And I'm actually a...I hope I'm not annoying to anyone. But I'm very pointed in saying, "This recurring meeting that we have if we keep just canceling it the day before every time, let's get this off our calendars. Let's make sure our calendars are telling the truth because I trust that thing very much." And two apps that I'm using right now that I've found really useful in the calendar world are MeetingBar, which I've talked about before. But it's a little menu bar application that shows the next meeting that's upcoming. And then I can click on it and see the list of them and easily join any video call associated, just a nice thing to keep the next thing on my calendar very top of mind, super useful, really love that. That's just open source and easy to run with. The other that I've been spending more and more time with lately is SavvyCal. SavvyCal is similar to Calendly. It's a tool for sharing a link to allow someone to schedule something on your calendar. And, man, it is an impressive piece of technology. I've been leaning into some of the fancier features of it of late. And it has an amazing amount of control, and I think a really well-designed sort of information architecture as well. It took me a little while to figure out how to do everything I wanted to do in it. But I wanted to be able to define a calendar link thing that I could share with someone that really constraints in the way that I wanted. Like, oh, don't let them schedule tomorrow, and make sure there's this much buffer between meetings. And don't let this calendar link schedule too many things on my calendar because I need to control my day, and give me some focus blocks. And they're not actually on my calendar, but please recognize that. And it basically supports all of these different ways of thinking and does an incredible job with it. As an aside, SavvyCal is created by Derrick Reimer, who is the co-host of The Art of Product Podcast, which is co other hosted by Ben Orenstein, former thoughtboter, creator of Upcase, and a handful of other things. So small world and all of that. But yeah, really fantastic piece of technology that I've been loving lately. STEPH: That's really cool. I have not heard of SavvyCal. I've used Calendly and used that a fair amount. And that is so awesome where you can just send it to people, and they can pick time on a calendar and do all the features that you'd mentioned. So it's good to know that there's SavvyCal as well. Well, pivoting just a bit, we have a listener question that I'm really excited to dig into. This question comes from fellow thoughtboter, Steve Polito. And Steve writes in that, "Hey, Bike Shed, I've got a question for you. I find it difficult to know if there's an existing method in a large class or a class that includes many concerns. How can I avoid writing redundant methods when working on a large project?" And Steve provided a really nice just contrived example where he's defined a class user that inherits from ApplicationRecord. And then comments, "Lots of methods making it really hard to scan this giant class. And then there's a method called formatted name. So it takes first name, adds a space, and then adds the user's last name. And then there are a lot more methods in between. And then, way down, there's another method called full name that does the exact same thing. Just to provide a nice example of how can you find a method that has existing logic that you want and avoid implementing essentially the same method and the same class?" So as someone who has worked on some legacy systems this year, I feel that pain. I feel the pain of where you have a really giant class, and that class may also include other modules. So then you have your range of all the methods that you may be looking through gets really widened. And you are looking for particular logic that you feel like may exist in the system, but you really just don't know. So I don't know if I have a concrete method for how you can find duplicate logic and avoid writing that other method. But some of the things that I do is I will initially go to the test. So if there's some logic that I'm looking for and I think it's in this class or I have a suspicion, I will first look to see what has test coverage. And I find that is just easier to skim where I can find, and I'll use grep, and search and just look for anything. In this particular case, let's use first name as our example. So I'm looking for anything that's going to collaborate with first name. Some of the other things that I'll do is I'll try to think of a business case where that logic is used. So, where are we displaying the user's full name? And if I can go to that page and see what's already in use, that may give me a hint to do we already have this logic? Is there something there that I should reuse, or is it something new that I'm implementing? And then if I really want to get fancy about it, for some reason that I really want to see all the methods that are listed, but I'm trying to get rid of some of the noise in the file, then I could programmatically scan through all the available methods by doing something like class.instance methods and passing in false. So we don't include the methods that are from superclasses, which can be very helpful. So that way, you're just seeing what scoped to that class. But then, let's say if you do have a class that is inheriting from other modules, then you may want to include those methods in your search. So to get fancier, you could look at that class' ancestor chain and then collect the classes or models that are custom to your application, and then look at those instance methods. And then you could sort them alphabetically. But you're still really relying on is there a method name that looks very similar to what I would call this method? So I don't know that that's a really efficient way. But if I just feel like there's probably already something in this space and I'm just looking for a clue or some name that's going to hint that something already exists, that's one way I could do it. To throw another wrench in there, I just remembered there are also private methods, and private methods don't get returned from instance methods. I think it's private instance methods is a method that you'd have to call to then include those in your search results as well. So outside of some deeper static analysis, this seems like a hard problem. This seems like something that would be challenging to solve. And then I guess the other one is I ask a friend. So I will often lean on if there's someone else at the team that's been there longer than me is I will just ask in Slack and say, "Hey, I want to do a thing. I'm worried this already exists, or I think it already exists. Does anybody have any clues or ideas as to where this might live?" I know I just ran through a giant list of ideas there. But I'm really curious, what are your thoughts? If you have a messier codebase and you're worried that you are reimplementing logic that already exists, but you're trying to make sure you don't duplicate that logic, how do you avoid that? CHRIS: Well, the first thing I want to say is that I find it really interesting that I think you and I came at this from different directions. My answer, which I'll come to in a minute, is more of the I'm not actually sure that this is that easy to avoid, and maybe that's not the biggest problem in the world. And then I have some thoughts downstream from that. But the list that you just gave was fantastic. That was a tour de force of how to understand and explore a codebase and try and answer this very hard question of like, does this logic already exist somewhere else? So I basically just agree with everything you said. And again, I'm deeply impressed with the range of options that you offer there for trying to figure this out. That said, sometimes codebases just get really large. And this is going to happen. I think the specific mention of concerns as sort of a way that this problem can manifest feels true. Having the user object and being like, oh man, our user object is getting pretty big. Let's pull something out into a concern as just a way to clean it up. That actually adds a layer of indirection that makes it harder to understand the totality of what's going on in this thing. And so personally, I tend to avoid concerns for that reason or at least at the model layer, especially where it's just a we got 1,000 methods here. Let's pull 200 of them into a file and maybe group them somewhat logically. That tends to not solve the problem in my mind. I found that it just basically adds a layer of indirection without much additional value. I will say in this particular case, the thing that we're talking about presenting the full name or the formatted name feels almost like a presentational concern. So I might ask myself, is there a presenter object, something that wraps around a user and encapsulates this? And then we as a team know that that sort of presentational or formatting logic lives in the presentation format or layer. Maybe I'm not entirely convinced of that as an answer. But it's just sort of where can we find organizational lines to draw within our codebases? I talked about query objects earlier. That's one case of this is behavior that I'll often see in classes as, say, a scope or something like that that I will extract out into a query object because it allows me to encapsulate it and break it out a little bit more but still have most of the nice pieces that I would want. So are there different organizational patterns that are useful? I think it's very easy to start drawing arbitrary lines within our codebases and say, "These are services." And it's like, what does that mean? That doesn't mean anything. App Services, that's not a thing, so maybe don't do that. But maybe there are formatters, queries, commands, those feel like...or presenters, queries, commands. Maybe those are organizational structures that can be useful. But switching to the other side of it, the first thing that came to mind is like, this is going to happen. As a codebase grows, this is absolutely going to happen. And so I would ask rather than how can I, as the developer, avoid doing this in the first place...which I think is a good question to ask. And again, everything you listed, Steph, is great. And I think a wonderful list of ways that you can actually try to avoid this. But let's assume it is going to happen. So then, what do we do downstream from that? One answer that comes to mind is code review. Code review is not perfect. But this is the sort of thing that often in code review I will be like, oh, I actually wrote a method that's similar to this. Can you take a look at that and see can we use only one of these or something like that? So I've definitely seen code review be a line of defense on this front. But again, stuff is still going to sneak through. And someday, you'll find it down the road. And that's the point in time that I think is most interesting. When you find this, can you fix it easily? Do you have both process-wise and infrastructure-wise the ability to do a very small PR that just removes the duplicate method, removes the usage of it, and consolidates on the one? It's like, oh, I found it. Here's a 10-line PR that just removes that method, changes the usage. And now we're good. And that can go through code review and CI very quickly. And we have a team culture that allows us to make those tiny changes on the regular to get them out to production as quick as possible so that we know that this is a good code change, all of that. I found there are teams that I've worked on where that process is much slower. And therefore, I will try and roll a change like that up into a bigger PR because I know that's the only way that it's really going to get through. Versus I've been on teams that have very high throughput is probably the best way to describe it. And on those teams, I find that the codebase tends to be in a healthier shape because it just naturally falls out of having a system that allows us to make changes rapidly with high trust, get them out into the world, et cetera. STEPH: This is that bug or inconsistency that's going to show up where on one page you have the user's full name. And then on another page, you have the user's full name, but maybe the last name is not capitalized, or there's just something that's slightly different. And then that's when you realize that you have two implementations of essentially the same logic that have differed just enough. I like how you pointed out that this is one of those things that as a codebase grows, it's probably going to happen, and that's fine. It's one of those if you do have duplicate logic, over time, based on your team's processes, you'll be able to then identify when it does happen, and then look for those preventative patterns for then how you organize your code. How quickly can you make that change? Can you just issue a PR that then removes one of them? But then look for ways to say, how are we going to help our future selves recognize that if we're looking for a user's full name, where's a good place to look for that? And then what's a good domain space or naming that we can give to then help future searchers be able to find it? I also really like your code review example because it does feel like one of those things that, yes, we want to catch it if we can, and we can leverage the team. But then also, it's not the end of the world if some of these methods do get duplicated. There's one other thing that came to mind that it's not really going to help prevent duplicate methods, but it will help you identify unused code. So it's the Unused tooling that you can run on your codebase. And that's something that would be wonderful to run on your codebase every so often. So that way, if someone has added...let's say there was a method that was full name but is not in use. It didn't have test coverage; that's why you didn't find it initially. And so you've introduced your own formatted name. And then, if you run unused at some point, then you'll hopefully catch some of those duplicate methods as long as they're not both in use. CHRIS: I think one more thing that I didn't quite say in my earlier portion about this. But in order to do that, to use Unuse or to have these sort of small pull requests that are going through, you have to have test coverage that is sufficient that you are confident you're not going to break the app. Because the day that you do like, oh, there's a typo here; let me fix it real quick. Or there's this method I'm pretty sure it's not used; let me rip it out. And then you deploy to production, and suddenly the error system is blowing up because, in fact, it was used but sneakily in a way that you didn't think of, and your test coverage didn't catch that. Then you don't have trust in the system, and everything slows down as a result of that. And so I would argue for fixing the root problem there, which is the lack of test coverage rather than the symptom, which is, oh, I made this change, it broke something. Therefore, I won't make small changes anymore. STEPH: Definitely. Yeah, that's a great point. CHRIS: So yeah, I don't have any answer. [laughs] My answers are like, I don't know, it's going to happen, but there's a lot of stuff organizationally that we can do. And granted, you gave a wonderful list of ways to actually avoid this. So I think the combination of our answers really it's a nice spectrum of thoughts on this topic. STEPH: I agree. I feel like we covered a very nice range all the way from trying to identify and then how to prevent it or how to help future people be able to identify where that logic lives and find it more easily. Also, at the end of the day, I like the how big of a problem is this? And it is one of those sure; we want to avoid it. But I liked how you captured that at the beginning where you're like, it's okay. Like, this is going to happen but then have the processes around it to then avoid or be able to undo some of that duplicate work. But otherwise, if it happens, don't sweat it; just look for ways to then prevent it from happening in the future. 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.Sponsored By:Scout: Scout APM is leading-edge application performance monitoring 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 performance abnormalities -- like N+1 queries, slow database queries, memory bloat, and 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 worldwide call Scout their best friend and try our error monitoring and APM free for 14-days, no credit card needed! And as an added bonus for Bikeshed listeners: Scout will donate $5 to the open-source project of your choice when you deploy. Learn more at scoutapm.com/bikeshed.Support The Bike Shed
undefined
Jan 18, 2022 • 35min

322: Toxic Traits

Happy New Year (for real)! Chris and Steph both took some end-of-year time off to rest and recharge. Steph talks about some books she enjoyed, recipes she tried, and trail-walking adventures with her dog, Utah. Chris' company is now in a good position to actually start hiring within the engineering team. He's excited about that and will probably delve into more around the hiring process in the coming weeks. Since they aren't really big on New Year's Eve resolutions, Steph and Chris answer a listener question regarding toxic traits inspired by the listener question related to large pull requests and reflect on their own. This episode is brought to you by ScoutAPM. Give Scout a try for free today and Scout will donate $5 to the open source project of your choice when you deploy. The Midnight Library by Matt Haig Tim Urban on Twitter How to Stop Time by Matt Haig Do the Next Right Thing Debugging Why Your Specs Have Slowed Down test-prof Tests Oddly Slow Might Be Bcrypt Become a Sponsor 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, spoiler, we actually may have lied in a previous episode when we said, "Hey, happy New Year," because, for us, it was not actually the new year. But this, in fact, is the first episode of the new year that we're recording, that you're hearing. Anyway, this is enough breaking the fourth wall. Sorry, listener. STEPH: [laughs] CHRIS: Inside baseball, yadda, yadda. I'm doing great. First week back. I took some amount of vacation over the holidays, which was great, recharging, all those sorts of things. But now we're hitting the ground running. And I'm actually really enjoying just getting back into the flow of things and, frankly, trying to ramp everything up, which we can probably talk about more in a moment. But how about you? How's your new year kicking off? STEPH: I like how much we plan the episodes around when it's going to release, and we're very thoughtful about this is going to be released for the new year or around Christmas time, and happy holidays to everybody. And then we get back, and we're like, yeah, yeah, yeah, we can totally drop the facade. [laughs] We're finally back from vacation. And this is us, and this is real. CHRIS: Date math is so hard. It just drains me entirely to even try and figure out when episodes are going to actually land. And then when we get here, also, you know, I want to talk about the fact that there was vacation and things, and the realities of the work, and the ebb and flow of life. So here we are. STEPH: Same. Yeah, I love it. Because I'm in a similar spot where I took two weeks off, which was phenomenal. That's actually sticking to one of the things we talked about, for one of the things I'm looking to do is where I take just more time off. And so having the two weeks was wonderful. It was also really helpful because the client team that I'm working with also shut down around the end of the year. So they took ten days off as well. So I was like, well, that's a really good sign of encouragement that I should also just shut down since I can. So it's been delightful. And I have very little tech stuff to share because I've just been doing lots of other fun things and reading fiction, and catching up with friends and family, and trying out new recipes. That's been pretty much my last two weeks. Oh, and walks with Utah. His training is going so well where we're starting to walk off-leash on trails. And that's been awesome. CHRIS: Wow, that's a big upgrade right there. STEPH: Yeah, we're still working on that moving perimeter so he knows how far he can go. Before then, he needs to stop and check on me. But he's getting pretty good where he'll bolt ahead, but then he'll stop, and he'll look at me, and then he'll wait till I catch up. And then he'll bolt ahead again. It's really fun. CHRIS: I like that that's the version of it that we're going for. This is not like you're going to walk alongside me on the trail; it's you're obviously going to run some distance out. As long as you check back in once every 20 feet, we're good; that’s fine. Any particularly good books, or recipes, or talks with friends to go with that category? But that one's probably a little more specific to you. STEPH: [laughs] Yes. There are two really good books that I read over the holidays. They're both by the same author. So I get a lot of books from my mom. She'll often pick up a book, and once she's done with it, she'll drop it off to me or vice versa. So the one that she shared with me is called The Midnight Library. It's written by Matt Haig, H-A-I-G. And it's a very interesting story. It's a bit sad where it's about a woman who decides that she no longer wants to live. And then, when she moves in that direction to go ahead and end her life, she ends up in this library. And in the library, every time she has made a different decision or made a decision in life, then there is a new book written about what that life is like. So then she has an opportunity to go explore all of these lives and see if there's a better life out there for her. It is really interesting. I highly recommend it. CHRIS: Wow. I mean, that started with, I'm going to be honest, a very heavy premise. But then the idea that's super interesting. I would, actually...I think I might read that. I tend to just read sci-fi. This is broadly in the space, but that is super interesting. There's an image that comes to mind actually as you described that. It's from Tim Urban, who's also known as Wait But Why. I think he posts under that both on Twitter, and then I think he has a blog or something to that effect. But the image is basically like, all of the timelines that you could have followed in your life. And everybody thinks about like, from this moment today. Man, I think about all of the different versions of me that could exist today. But we don't think about the same thing moving forward in time. Like, what are all the possibilities in front of me? And what you're describing of this person walking around in a library and each book represents a different fork in the road from moving forward is such an interesting idea. And I think a positive reframing of any form of regret or looking back and being like, what if I had gone the other way? It's like, yeah, but forward in time, though. I'm very intrigued by this book. STEPH: Yeah, it's really good. It definitely has a strong It's a Wonderful Life vibe. Have you ever watched that movie? CHRIS: Yes, I have. STEPH: So there's a lot of that idea of regret. And what if I had lived differently and then getting to explore? But in it's A Wonderful Life, he just explores the one version. And in the book, she's exploring many versions. So it's really neat to be like, well, what if I'd pursued this when I was younger, had done this differently? Or what if I got coffee instead of tea? There are even small, little choices that then might impact you being a different person at a point in time. The other book that I read is by the same author because I enjoyed Midnight Library so much that I happened to see one of his other books. So I picked it up. And it's called How to Stop Time. And it's about an individual who essentially lives a very long time. And there are several people in the world that are like this, but he lives for centuries. But he doesn't age, or he ages incredibly slowly, at a rate that where say that he's 100 years old, but he'll still look 16 years old. And it's very good. It's very interesting. It's a bit more sad and melancholy than I typically like to read. So that one's good. But I will add that even though I described the first one, it has a sad premise; I found The Midnight Library a little more interesting and uplifting versus the other one I found a bit more sad. CHRIS: All right. Excellent additional notes in the reading list here. So you can opt like, do you want a little bit more somber, or do you want to go a little more uplifting? Yeah, It's a Wonderful Life path being like, starts in a complicated place but don't worry, we'll get you there in the end. STEPH: But I've learned I have to be careful with the books that I pick up because I will absorb the emotions that are going on in that book. And it will legit affect me through the week or as I'm reading that book. So I have to be careful of the books that I'm reading. [laughs] Is that weird? Do you have the same thing happen for when you're reading books? CHRIS: It's interesting. I don't think of it with books as much. But I do think of it with TV shows. And so my wife and I have been very intentional when we've watched certain television shows to be like, we're going to need something to cut the intensity of this show. And the most pointed example we had was we were watching Breaking Bad, which is one of the greatest television shows of all time but also just incredibly heavy and dark at times, kind of throughout. And so we would watch an episode of Breaking Bad. And then, as a palate cleanser, we would watch an episode of Malcolm in the Middle. And so we saw the same actor but in very different facets of his performance arc and just really softened things and allowed us to, frankly, go to bed after that be able to sleep and whatnot but less so with reading. So I find it interesting that I have that distinction there. STEPH: Yeah, that is interesting. Although I definitely feel that with movies and shows as well. Or if I watch something heavy, I'm like, great, what's on Disney? [laughs] I need to wash away some of that so I can watch something happy and go to sleep. You also asked about recipes because I mentioned that's something I've been doing as well. There's a lot of plant-based books that I've picked up because that's really my favorite type of thing to make. So that's been a lot of fun. So yeah, a lot of cooking, a lot of reading. How about you? What else is going on in your world? CHRIS: Well, actually, it's a super exciting time for Sagewell Financial, the company that I've joined. We are closing our seed financing round, which the whole world of venture capital is a novel thing that I'm still not super involved in that part of the process. But it has been really interesting to watch it progress, and evolve, and take shape. But at this point, we are closing our seed round. Things have gone really well. And so we're in a position to actually start hiring, which is a whole thing to do, in particular, within the engineering group. We're hiring, I think, throughout the company, but my focus now will be bringing a few folks into the engineering team. And yeah, just trying to do that and do that well, do that intentionally, especially for the size of the team that we have now, the sort of work that we're doing, et cetera, et cetera. But if anyone out there is listening, we are looking for great folks to join the team. We are Ruby on Rails, Inertia, TypeScript. If you've listened to the show anytime recently, you've heard me talk about the tech stack plenty. But I think we're trying to do something very meaningful and help seniors manage finance, which is a complicated and, frankly, very underserved space. So it's work that I deeply believe in, and I think we're doing a good job at it. And I hope to do even a better job over time. So if that's at all interesting, definitely reach out to me. But probably in the coming weeks, you'll hear me talk more and more about hiring and technical interviews and all of those sorts of things. I got to ramp myself back up on that entire world, which is really one of those things that you should always be doing is the thought that I have in my head. Now that I'm in a position to be hiring, I wish I'd been half-hiring for the past three months, but I'll figure it out. It'll be fine. STEPH: That's such a big undertaking. Everything you're saying resonates, but also, it's like that's a lot of hard work. So if you're not in that state of really being ramped up for hiring, I understand why that would be on the backburner. And yeah, I'm excited to hear more. I've gotten to hear some more of the product details about Sagewell, but I don't think we've really talked about those features here on the show. So I would love it if we brought some more of the feature work and talked about specifically what the application does. I am intrigued speaking of how much energy goes into hiring. Where are you at in terms of how much...like, are there any particular job boards that you're going for? Or what's your current approach to hiring? CHRIS: Oh, that's a great question. I have tweeted once into the world. I have a draft of a LinkedIn post. This is very much I'm figuring out as I go. It's sort of the nature of a startup as we have so many different things to do. And frankly, even finding the time to start thinking about hiring means I'm taking time away from building features and growing out other aspects. So it's definitely a necessary thing that we're doing at this point in time. But basically, everything we're doing is just in time compiling and figuring out what are the things that are semi-urgent right now? And to be honest, I like that energy overall. I've always had in the back of my mind that I like this sort of work and this space, especially if you can do it intentionally. It shouldn't feel like everything's on fire all the time, but it should feel like a lot of constraints that force you to make decisions quickly, which, if we're being honest, I think that's something that is not my strongest suit. So it's something that I'm excited to grow that muscle as part of this work. But so, with that in mind, at this point, my goal is to just start getting the word out there into the world that we are looking to hire and get people interested and then, from there, build out what's the interview process going to look like? I will let you know when we get there; I will. I will figure that out. But it's not something that I've...I haven't actually very intentionally thought about all of this. Because if I were to do that, it would delay the amount of time until I actually say into the world, "Hey, we're hiring." So I very purposely was like, I just need to say this into the world and then continue doing the next steps in that process. I'm prone to the perfect is the enemy of the good just trying to like, I want to have a complete plan and a 27-step checklist, and a Gantt chart, and a burndown. And before I take any first action and really trying to push back, I'm going to be like, no, no, just do something, just take a step in the right direction. There's actually a blog post that comes to mind, which is by Dave Rupert, who is a former guest on this podcast. It was wonderful getting to interview him. But he wrote a blog post. The title of it is Do the Next Right, which is a line from a song in the movie Frozen 2, I believe. He is like, all right, stick with me here. And I know this is a movie for kids, maybe. But also, this is a very meaningful song. And he framed it in a way that actually was surprisingly impactful to me. And it's that idea that I'm holding on to of you can't do it all, and you can't do it perfectly. Just do the next right thing. That's what you're going to do. So we'll link to that blog post in the show notes. But that's kind of where I'm at. STEPH: I love that. I'm looking forward to reading that because that has been huge for me. I used to be held back by that idea of perfection. But then I realized other people were getting more work done more quickly. And so I was like, huh, maybe there's something to this just doing the next thing versus waiting for perfection that is really the right path. So, how do folks reach out to you? Should they reach out to you on Twitter or email? What's best for you? CHRIS: Oh yeah, Twitter. This is all probably going to be said at the end of the show as well. But Twitter @christoomey. ctoomey.com is my blog. I'm on GitHub. I make it very easy to contact me because I haven't regretted that up to this point in my life. So basically, anywhere you find me on the internet, you will be able to email me or DM me or any of the things. I'm going to see how long I can hold on to that. I want to hold on to that forever. I want just a very open-door policy. So that's where I'm at right now, but any of those starting points. And bikeshed.fm website will somehow link to me in any of the various forums, and they're all kind of linked to each other, so any of those are fine. I will happily take inquiries via any of the channels. STEPH: Cool. Well, I'm excited to hear about how it goes. CHRIS: Me too, frankly. But in a very small bit of little tech news or tech happenings from my holiday time, this was actually just before I started to go on break for the holidays. I had noticed that the test suite was getting very slow, like very, very slow but on my machine. It was getting a little bit slow on CI, but the normal amount where we just keep adding new things. And we're adding a lot of feature specs because we want to have that holistic coverage over the whole application, and we can, so for now, we're doing that. But our spec suite had gotten up to six-ish minutes on CI and had a couple of other things. We have some linting and some TypeScript and things like that. But on my machine, it was very slow. So I hadn't run the full spec suite in a long time. But I knew that running any individual spec took surprising amounts of time. And in the back of my head, I was like; I guess I hadn't configured Spring. That seems weird. I probably would have done that, but whatever. And I'd never pushed on it more until one day I ran the specs. I ran one model spec, and it took 30 seconds or something like that. And I was like, well, that's absurd. And so I started to look into it. I did some scanning around the internet. There was a wonderful post on the Giant Robots blog about how to look through things from Mike Wenger, a wonderful former thoughtboter. Unfortunately, none of the tips in there were anything meaningful for me. Everything was as I expected it to be. So I set it down. And there were a couple of times that this happened to me where I'd be like, this is frustrating. I need to look into this a little bit more, but it was never worth investing more time. But I mentioned it in passing to one of the other developers on the team. And as a holiday gift to me, this person discovered the solution. So let me describe a little bit more of what we've got working on here. On CI, which in theory is less powerful than my new, fancy M1 MacBook, on CI, we take about six minutes for the test suite. On my computer, it was taking 28 minutes and 30 seconds. So that's what we're working with. The factories are all doing normal things. We're not creating way too many database records or anything like that. So any thoughts, anything that you would inspect here? STEPH: Ooh, you've already listed a number of good things that I would check. CHRIS: Yeah, I took all the easy ones off the list. So this is a hard question at this point. To be clear, I had no ideas. STEPH: Could you tell if there's a difference if it's like the boot-up time versus the actual test running? CHRIS: Did that check; it is not the boot-up time. It is something that is happening in the process of running an individual spec. STEPH: No, I'm drawing a blank. I can't think of what else I would check from there. CHRIS: It's basically where I was at. Let me give you one additional piece of data, see if it does anything for you. I noticed that it happened basically whenever executing any factory. So I'd watch the logs. And if I create this record, it would do roughly what I expect it to. It would create the record and maybe one or two associated records because that's how Factory Bot works. But it wasn't creating a giant cascade or waterfall of records under the hood. If we create a product, the product should have an associated user. So we'll see a product and a user insert. But for some reason, that line create whatever database record was very, very slow. STEPH: Yeah, it's a good point, looking at factories because that's something I've noticed in triaging other tests is that I will often check to see how many records are created at a certain point because I've noticed there's a test where I think only one record is created, but I'll see 20. And that's an interesting artifact. But you're not running into that. But it sounds like there's more either some callback or transaction or something that's getting hung up and causing things to be slow. CHRIS: I love those ideas. I didn't even know those were sort of ideas in the back of my head. I didn't know how to even try and chase that down. There was nothing in the logs. I couldn't see anything. And again, I just kept giving up. But again, this other developer on the team found the answer. But at this point, I'll just share the answer because I think we've run out of the good bits of the trivia. It turns out bcrypt was the answer. So password-hashing was incredibly slow on my machine. What was interesting is I mentioned this to the other developer because they also have an M1. But there are three of us working on the project. The third developer does not have the M1 architecture. So that was an interesting thing. I was like, I feel like this maybe is a thing because we're both experiencing this, but the other developer isn't. So it turns out bcrypt is wildly slow on the M1 architecture, which is sort of interesting as an artifact of like, what is password hashing, and how does it work? And in normal setups, I think the way it works is Devise will say by default, "We're going to do 12 runs of bcrypt." So like take the password, put it into the hashing algorithm, take the output, put it back into the hashing algorithm, and do that loop 12 times or whatever. In test mode, it often will configure it to just run once, but it will still use the password hashing. Turns out even that was too slow for us. So we in test mode enabled it so that the password hashing algorithm was just the password. Don't do anything. Just return it directly. Turn off bcrypt; it's too painful for us. But it was very interesting to see that that was the case. STEPH: Yeah, I don't like that answer. [laughs] I'm not a fan. That is interesting and tricky. And I feel like the only way I would have found that...I'm curious how they found it because I feel like at that point, I would have started outputting something to figure out, okay, where is the slow process? What's the thing that's taking so long to return? And if I can't see tailing the test logs, then I would start just using a PUT statement to figure out what's taking a long time? And start trying to troubleshoot from there. So I'm curious, do you know how they identified that was the core issue? CHRIS: Yes, actually. I'm looking back at the pull requests right now. And I'm mentioning that this was related to the M1 architecture, but I don't think that's actually true because the blog post that they're linking to is Collective Idea blog post: Tests Oddly Slow? Might be bcrypt. And then there's a related Rails issue. They used TestProf, which is a process that you can run that will examine, I think the stack trace and say where are we spending the most time? And from that, they were able to see it looks like it's at the point where we're doing bcrypt. And so that's the answer. As an aside, my test suite went from 28 minutes and 30 seconds to 1 minute and 30 seconds with this magical speed up. STEPH: Nice. That's a great idea, TestProf. I don't know if I've used that tool. It rings a bell. But that's an awesome sales pitch for using TestProf. CHRIS: Similarly, I don't think I'd ever use it before. But it truly was this wonderful holiday gift. Because the minute I switched over to this branch, I was like, oh my God, the tests are so fast. I have one of those fancy, new fast computers, [laughs] and now they're so fast. STEPH: Wait, you had to switch to a branch? I figured it was something that you had to do special on your machine. So I'm intrigued how they fixed it for you, and then you switched to a branch and saw the speed increase. CHRIS: So they opened a pull request. And that pull request had the change in the code. So it was a code-level configuration to say, "Hey, Devise, when you do the password hashing thing, maybe just don't, maybe be easy for a moment," [laughter] but only in the test configuration. So all I had to do was check out the branch, and then that configuration was part of the Rails helper setup, and then we were good to go from there. I added an extra let me be terrified about this because the idea of not hashing passwords in production is terrifying. So let me raise...I put a couple of different guards against like, this should only ever run in test. I know it's in the spec support directory, so it shouldn't. Let me just add some other guards here just to superduper make sure we still hash passwords in production. STEPH: Devise has a bcrypt chill mode. Good to know. [laughs] And I like all the guards you put in place too. CHRIS: Yeah, it was really frankly such a relief to get that back to normal, is how I would describe it. But yeah, that's a fun little testing, and password hashing, and little adventure that I get to go on. 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. STEPH: So I have something that I've been wanting to ask you, and it's not tech-related. But we can make this personal and work however we want to tackle it. But there is a previous episode where we read a listener question from Brian about their self-diagnosed toxic trait being large pull requests. And Brian was being playful with the use of the term toxic trait. But it got me thinking, it's like, well, what is my toxic trait? And it seems like a fun twist on you, and I aren't really big on New Year's Eve resolutions. And in fact, I think you and I are more like if we're interested in achieving a goal, we'd rather focus on building a habit versus this specific, ambiguous we're going to publish ten blogs this year. But rather, I'd rather sit down and write for 15 minutes each day. And it seemed like a fun twist instead of thinking about what are my toxic traits, personal, at work? Large pull request is a really fun example. So I'll let you choose. I can go first, or you can go first, but I'm excited to hear your thoughts on this one. CHRIS: I think I've been talking too much. So let's have you go first at this point/ also, I want a few more seconds to think about my toxic trait. STEPH: [laughs] All right, I have a couple. So that's an interesting point start there [laughs], but here we are. So I was even bold because I asked other people. Because I'm like, well, if I'm going to be fully self-aware, I can't just...I might lie to myself. So I'm going to have to ask some other people. So I asked other folks. And my personal toxic trait is I am tardy. I am that person who I love to show up 5, 10, 15 minutes late. It's who I am. I don't find it a problem, but it often bothers other people. So that is my informed toxic trait. That might be a strong term for it. But that's the one that gives people the most grief. CHRIS: Interesting. I do find the framing of I don't find my own tardiness to be a problem as a really interesting sort of lens on it. But okay, it's okay. STEPH: I see it as long as I'm getting really good quality time with someone; if I'm five minutes late, I'm five minutes late. I think the voice going high means I'm a little defensive. [laughs] CHRIS: But at least you're self-aware about all of these aspects. [laughs] That's critical. STEPH: I am self-aware, and most of the people in my life are also self-aware, although I do correct that behavior for work. That feels more important that I be on time for everything because I don't want anyone to feel that I am not valuing their time. But when it comes to friends and family, they thankfully accept me for who I am. But then, on the work note, I started thinking about toxic traits there. And the one I came up with is that I'm a pretty empathetic person. And there's something that I learned that's called toxic empathy. And it's when you let people's emotions hijack your own emotions, or you'll prioritize someone else's physical or mental health over your own. So, for example, it could be letting another person's anxiety and stress keep you from getting your current tasks and responsibilities done. And there's a really funny tweet that I saw where someone says, "Hey, can I vent to you about something?" And the first person telling it from their perspective they're crying in the middle of a breakdown. And they're like, "Yeah, sure, what's up?" And I felt seen by that tweet. I was like, yeah; this seems like something I would do. [laughs] So over time, as something I'm aware of about myself, I've learned to set more boundaries and only keep relationships where equal support is given to both individuals. And this circles back to the book anecdote that I shared where I had to be careful about the books that I read because they can really affect my mood based on how the characters are doing in that book. So yeah, that's mine. I have one other one that I want to talk about. But I'm going to pause there so you can go. CHRIS: Okay, fun. [laughs] This is fun. And it is a challenging mental exercise. But it is also, I don't know, vulnerable, and you have to look inside and all that. I think I poked at one earlier on as we were talking, but the idea of perfect is the enemy of the good. And I don't mean this in the terrible like; what’s your worst trait in a job interview? And you're like, "I'm a perfectionist." I don't mean it in that way. I mean, I have at times struggled to make progress because so much of me wants to build the complete plan, and then very meticulously worked through in exactly the order that I define, sort of like a waterfall versus agile sort of thing. And it is an ongoing very intentional body of work for me to try and break myself off those habits to try and accept what's the best thing that I can do? How can I move forward? How can I identify things that I will regret later versus things that are probably fine? They're little messes that I can clean up, that sort of thing. And even that construing it as like there's a good choice and a bad choice, and I'm trying to find the perfect choice. It's like almost nothing in the world actually falls into that shape. So perfect is the enemy of the good is a really useful phrase that I've held onto that helps me. And it's like, aiming for that perfection will cause you to miss the good that is available. And so, trying to be very intentional with that is the work that I'm doing. But that I think is a toxic trait that I have. STEPH: I really like what you just said about being able to identify regrets. That feels huge. If you can look at a moment and say, "I really want to get all this done. I will regret if I don't do this, but the rest of it can wait," that feels really significant. So the other one that I wanted to talk about is actually one that I feel like I've overcome. So this one makes me happy because I feel like I'm in a much better space with it, but it's negative self-talk. And it's essentially just how you treat yourself when you make a mistake. Or what's your internal dialogue throughout the day? And I used to be harsh on myself. If I made a mistake, I was upset, I was annoyed with myself, and I wouldn't have a kind voice. And I don't know if I've shared this with you. But over time, I've gotten much better at that. And what has really helped me with it is instead of talking to myself in an unkind voice, I talk to myself how someone who loves me will talk to me. I'm not going to talk to a friend in a really terrible, mean voice, and I wouldn't expect them to talk to me. So I channel someone that I know is very positive and supportive of me. And I will frame it in that context. So then, when I make a mistake, it's not a big deal. And I just will say kind things to myself or laugh about it and move through it. And I found that has been very helpful and also funny and maybe a little embarrassing at times because when pairing, I will talk out loud to myself. And so I'll do something silly, and I'll laugh. I'm like, "Oh, Stephanie," that was silly. And the other person hears me say that. [laughs] So it's a little entertainment for them too, I suppose. CHRIS: Having observed it, it is charming. STEPH: It's something that I've noticed that a lot of people do, and we don't talk about a lot. I mean, there's imposter syndrome. People will talk about that. But we don't often talk about how critical we are of ourselves. It's something that I will talk to people who I highly admire and just think they're incredibly good at what they do. And then when they give me a glimpse into how they think about themselves at times or how they will berate themselves for something they have done or because they didn't sit down for that 15 minutes and write per day, then it really highlights. And I hope that if we talk about this more, the fact that people tend to have such a negative inner critical voice, that maybe we can encourage people to start filtering that voice to a more kind voice and more supportive voice, and not have this unhelpful energy that's holding us back from really enjoying our work and being our best self. CHRIS: That's so interesting to hear you say all of that for one of your traits because it's very similar to the last one for myself, which is I find that I do not feel safe unless (This is going to sound perhaps boastful, and I definitely do not mean it as boastful.) but unless I'm perfect. I guess the standard that I hold myself to versus the standard that I hold others to are wildly different. Of course, for other people, yes, bugs will get into the code, or they may misunderstand something, or they may miss communicate something, or they may forget something. But if I do that, I feel unsafe, which is a thing that I've slowly come to recognize. I'm like, well, that shouldn't be true because that's definitely not how I feel about other people. That's not a reasonable standard to hold. But that needing to be perfectly secured on all fronts and have just this very defensible like, yeah, I did the work, and it's great, and that's all that's true in the world. That's not reasonable. I'm never going to achieve that. And so, for a long time, there have been moments where I just don't feel great as a result of this, as a result of the standard that I'm trying to hold myself to. But very similarly, I have brought voices into my head. In my case, I've actually identified a board of directors which are random actual people from my world but then also celebrities or fake people, and I will have conversations with them in my head. And that is a true thing about me that I'm now saying on the internet, here we are. STEPH: [laughs] CHRIS: And I'm going to throw it out there. It is fantastic. It is one of my favorite things that I have in my world. As a pointed example of a time that I did this, I was running a race at one point, which I occasionally will run road races. I am not good at it at all. But I was running this particular race. It was a five-mile January race a couple of years back. And I was getting towards the end, and I was just going way faster than I normally do. I was at the four-mile mark, and I was well ahead of pace. I was like, what is this? I was on track to get a personal record. I was like, this is exciting. But I didn't know if I could finish. And so I started to consult the board of directors and just check in with them and see what they would think about this. And I got weirdly emotional, and it was weirdly real is the thing that was very interesting, not like I actually believed that these people were running with me or anything of that nature. But the emotions and the feelings that I was able to build up in that moment were so real and so powerful and useful to me that it was just like, oh, okay, yeah, that's a neat trick. I'm going to hold on to that one. And it has been continuously useful moving forward from that of like, yeah, I can just have random conversations with anyone and find useful things in that and then use that to feel better about how I'm working. STEPH: I so love this idea. And I'm now thinking about who to put on my board of directors. [laughs] CHRIS: I'm telling you, everybody should have one. As I'm saying this, there is definitely a portion of me that is very self-conscious that I'm saying this on the internet because this is probably one of the weirdest things that I do. STEPH: [laughs] CHRIS: But it is so valuable. And it's one of those like; I like getting over that hump of like, well, this is an odd little habit that I have, but the utility that I get from it and the value is great. So highly recommend it. It's a fun game of who gets to go on your board. You can change it out every year. And it is interesting because the more formed picture that you have of the individual, the more you can have a real conversation with them, and that's fun. STEPH: So, as I'm working on forming a board of directors, how do you separate? Is it based on one person is running work and one is finance? How does each person have a role? CHRIS: So there are no rules in this game. [laughs] This is a ridiculous thing that I do. But I find value in it's sort of vaguely the same collection of individuals. Some of them are truly archetypal, even fictitious characters. As long as I can have a picture in my head of them and say, "What would they say in a situation?" If you're considering, say, moving jobs? What would Arnold Schwarzenegger have to say about that? And you'd be surprised the minute you ask it in your head; your brain is surprisingly good at these things. And it's like, let me paint The Terminator yelling at you to get the new job. STEPH: [laughs] CHRIS: Not get to the chopper, but get the new job. And it's surprisingly effective. And so I don't have a compartmentalized like, this is my work crew, this is my life crew. It's a nonsense collection of fake people in my head that I get to talk to. I'm saying this on the internet; here we are. [laughs] STEPH: That makes sense to me, though, because as you're describing that situation, I do something similar, but I've just never thought about it in these concrete terms where I have someone in mind, and it's a real person in my life who are my confidence person. They're the one that I know they are very confident. They're going to push for the best deal for themselves. They're going to look out for themselves. They're going to look out for me. They're going to support me. I have that person. And so, even if I can't talk to them in reality, then I will still channel that energy. And then I have someone else who's like my kind filter, and they're the person that's going to be very supportive. And you make mistakes, and it's not a big deal, and you learn, and you move on. And so I have those different...and in my mind, I just saw them as coaches. Instead of board of directors, I just see them as different things that I don't see as strong in my character. And so I have these coaches in those particular areas that then I will pull energy from to then bolster myself in a particular way or skill. This was fun. I'm so glad we talked about this because that is very insightful to you, and for me as well, and to myself. CHRIS: Yeah, we went deep on this episode. STEPH: No tech but lots of deep personal insight. CHRIS: I talked a little bit about bcrypt. [laughs] You can't stop me from talking about tech for an entire episode. But then I also talked about my board of directors and the conversations I have with myself, so I feel like I rounded it out pretty good. STEPH: It's a very round episode. CHRIS: Yeah, I agree. And with that roundedness, 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: 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.Sponsored By:Scout: Scout APM is leading-edge application performance monitoring 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 performance abnormalities -- like N+1 queries, slow database queries, memory bloat, and 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 worldwide call Scout their best friend and try our error monitoring and APM free for 14-days, no credit card needed! And as an added bonus for Bikeshed listeners: Scout will donate $5 to the open-source project of your choice when you deploy. Learn more at scoutapm.com/bikeshed.Support The Bike Shed
undefined
Jan 11, 2022 • 40min

321: Leaving Breadcrumbs

Steph tells a cute story about escape artist huskies, and on a technical note, shares a journey in regards to class variables and modules inheritance. Chris talks about how he's starting to pursue analytics and one of the things that he's struggling with that he's always historically struggled with is the idea of historical data. He's also noticed a lack of formalization of certain things and is working with his team to remedy that. This episode is brought to you by ScoutAPM. Give Scout a try for free today and Scout will donate $5 to the open source project of your choice when you deploy. Mike Burns: How to Skim a Pull Request RSpec Documentation Don't Let the Internet Dupe You, Event Sourcing is Hard Datomic time_for_a_boolean Sentry Become a Sponsor 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, it's an entirely new year. What is new in your new year? STEPH: Well, the year is off to an interesting start because we helped rescue a husky. CHRIS: Rescue as in now this is your dog or rescue as in the dog was trapped in a well, and another dog told you about the dog being trapped in a well, and then you helped the trapped? [laughs] Which of those situations are we working with? STEPH: [laughs] I'm really wishing it was the second version [laughs] where there's a dog that tells me about another dog trapped in a well. No, this is a third version where there was a husky that was wandering around the gym that we go to. And so Tim, my husband, called and said that "There's this husky, and he's super sweet, but he seems very lost." And our gym is located near a major road, and so we were worried that he was going to wander about and get hit. So I hopped into our car and took a crate and a leash, and he hopped right in. Clearly, he belonged to somebody; he'd just escaped. So he hops right in, and then we bring him home. But I put him in the backyard because I want to keep him separate from our dog, Utah, just because I don't know this dog, and I want to keep him safe. And I go back inside to grab a few things. I come back out, and the husky is gone. And I'm like, well, shit. [laughs] Now I'm starting to understand why this husky is missing or why this husky seemed lost. So then I started looking for the husky, and Tim comes home. He's helping me look for the husky. And it was one of those awful moments where we live near...it's not a major road, but people tend to speed on it. And the husky and I happen to see each other across the road. And so the husky was like, oh, human friend and starts coming across the road towards me. And there's this large SUV that's also coming from the other direction. I'm like, oh, this is it. This is my nightmare. This is becoming real. This dog is about to get hit. Thankfully, the driver saw the husky and stopped in time, so everything was fine. And the husky just finished trotting across the road to me, brought him in, kept him in the kennel in the garage. We didn't have any backyard adventures after that. The husky then thanked us by howling most of the night. [laughs] So this poor husky has had an adventure. We've had an adventure. And then, around 4:30 in the morning, I go out because I'm checking on the husky and going to let him out. And I'm scrolling on the app called Nextdoor. And I see that someone posted a picture of this exact husky that's like, "Please help me find my dog." And I was like, yes. Because we were going to have to take him to a county shelter or at least go see if he had a chip so then we could return him. But thankfully, we found the owner. I found out the husky's name is Sebastian. And then we had him for a few more hours, and then we had a wonderful husky and human reunion. CHRIS: That story had everything. It had ups; it had downs; it had huskies. It had escape artist huskies, in fact. I have...this is only through Reddit because that's how people learn about things in the world, but huskies are a rather vocal dog breed. So when you say the dog was howling, huskies have a particular way of almost singing, and it kind of sounds like yelling rather than more traditional dog sounds. Was that the experience you had? STEPH: Luckily, it wasn't too bad. His howling was more just; he didn't want to be in the crate. He seems like an indoor dog. So he's like, what am I doing outside in the garage? I should be indoors. And so he wasn't too loud. It was more he was just bemoaning his situation. But our dog Utah could hear him upset in the garage. And so that was also getting Utah upset because he didn't understand why there was a dog so close. And that was what led to the sleepless night because we couldn't get both of them to calm down. Because then, as soon as one of them calm down, the other one would get the other one riled. CHRIS: As it so often happens. STEPH: I'm so grateful that it turned out to be a happy story, though. That part was wonderful. And if we see the husky again, now we know his name is Sebastian and that he'll just come home with us. [chuckles] And we'll know how to return him since he seems to be an escape artist. CHRIS: And we were best friends forever. STEPH: On a more technical note, I have quite the journey to share in regards to class variables and modules inheritance. But before I dive in, I'm curious, what's new in your world? CHRIS: Oh. Well, I'm excited to dig into that story. But I've got two smaller things in my world this week that are top of mind. I don't really have answers on them. I have more questions. One is we're starting to pursue analytics. We want to try and understand our system a little bit better. What is the experience of our users? How are they coming into the system? What are they doing? How long does it take them to do the things that we want them to do? All those sorts of questions you want to be able to answer about your application. And one of the things that I'm struggling with that I've always historically struggled with is the idea of historical data. So data changes over time, and often we actually want to know about those transition points. We want to know about the different states that a user or any record in the system has been in. And I'm finding myself feeling the same pain that I felt many times and starting to think again about the relevant options out there in the world. To give a slightly more pointed example of what we're dealing with, users come in, and then there are a few steps for them to actually sign up for the application. And so their user record or their application, if you will, will go through a couple of different states. So they can be basically approved directly, and now they're an active user of the system, that's one option. But they can also end up in a state where they're pending review. And then eventually, depending on the outcome of that review, whether it's manual or someone intervenes or what have you, then eventually they can transition to either being denied or being accepted. And then they'll again be an active user. And so there's a question now of how many of the users that end up in that pending state end up transitioning into active. And as I looked at the database, I was like, I do not have this information right now. I know their current state. And the logs could tell me all of this. We don't have proper log archiving right now. And I also don't have a system for, like, let me pull down gigabytes of logs and try and sift through that to understand the answer, especially for something domain level like this. But this is one specific example that represents a category of things in my mind. The stuff that I've looked at in this space otherwise is Event Sourcing. So the idea that rather than having a discrete representation of the state of your application, you store every event as an individual log, essentially of like user did X, thing happened, Y occurred. And then, at any given point, you need to know about the state of your system; you just reduce all of those events through some magical reducer that produces the current state. I also very recently read an article called Event sourcing is Hard. So I have that in my head as a counterpoint. This seems like a thing that is non-trivial to do, makes sense for a certain scale. But of course, like anything else, it has its trade-offs. Another thing that I've looked at and never really pursued mostly because it's in a different ecosystem, is Datomic, D-A-T-O-M-I-C, which I think I've mentioned before. But it's a database that actually stores data in this historical format. And so you can ask for the current value, but then you can also ask for what are all the states that this user has been in? And what are the timestamps of those changes? One small thing that we do have that I really like...so this is one example of us; I think leaning into wanting to have more information, higher fidelity information, is often we want to know something like was this ticket paid? Did someone pay for this ticket? And so paid is a BooleanProperty on this ticket record within our system. So the ticket can be held for a little while and eventually gets paid. And now, yes, it has been paid for. It is good. You can use it. But often, we want to know not just that it's paid but when it was paid. And so there's a gem that we are using on the project called time_for_a_boolean by former thoughtboter, Caleb Hearth. And it does a wonderful job of basically instead of storing a Boolean value in the database, you store a timestamp. But then the Boolean can be inferred. If there is a value, if there's a timestamp for that record in the database, then there are a bunch of helper methods that get introduced that say, like, paid? That's now a method that I can ask, and it will tell us that. But we can also find the paid_at, paid_at value. And so we have this higher fidelity data when we need it, but we can also collapse it down to the simpler representation. Because most often, all we need to know is, have they paid for it? Cool, then they're good. They can come into the concert, that sort of thing. But yeah, this is a broader question that I don't have a great answer to. I think Postgres and Rails and just the nature of how we approach these applications pushes us in a certain direction. Another thing I'm exploring is downstream analytic systems. What if I send a bunch of events to them, and they act as a half-event sourcing type thing? But yeah, this is going to be, I think, an open question for me for a while. STEPH: Yeah, you said a lot of really good options. When you're talking about in our ecosystem, we get pushed in one direction or the other that makes me think of the projects that I've been on. Typically, what they'll reach for first is something like a Papertrail. So then, that way, they can check for the historical versions of an object and how it was changed and see who changed it. That's one way to track the logs. I like the idea that if you can outsource it and send all of those events to a logging system and then essentially ask for that data back as you need it. You made me think of a recent project as well where we needed to track the state. So it was a patient matching system. And we really needed to know when a patient match was created or disconnected and then who did that and perhaps for what reason. And to ensure that we had as much information as possible, we took that opportunity to just create a record for it. So we had a patient match record or...I forgot the name of the other one where we created where a patient did not have a match. But we were creating a record every time someone did that. Granted, probably that’s not going to happen nearly as often as someone paying for an event or the situations that you're describing. This was ideally infrequently that someone was going to unmatch a patient because it meant that our system had matched people that shouldn't be matched, and then a human had intervened. But yeah, it's interesting the space that you're in. And you listed all the good things that I would have thought of. CHRIS: I think you listed Papertrail, which is one that I hadn't actually thought of yet for this particular instance. This only came up earlier today also. So this is new in my head that I'm really being pushed in this direction. But I think Papertrail could be a good solution for where we're at. But it is one of those where you often don't know the thing you want to know. And I'm terrified of losing data of like; I had the data. I knew it at one point in time, but now I can't reknow it in the future because I didn't write it down. That's one of the things that I just don't want to happen in the world. And so finding those ways of like, how can we architect a system so that we can do the normal, straightforward, boring things most of the time but then when we need to expand out the analytics dimension of the system that we're working on...and trying to thread that needle and find the ideal optimization on both sides is a tricky one. But yeah, I'll definitely take another look at Papertrail and see if that...at a minimum, I think that's a good solution for where we're at now. And then this is going to be a thought that's going to roll around in the back of my head for a while. So if I come up with anything else, perhaps a grander solution, I'll certainly bring that back to The Bike Shed. But yeah, what else is up in your world? I want to hear the story of the class variables. STEPH: Well, it is quite a journey. So I hope you're ready. Specifically, I was pairing with Joël, who was working on fixing a test that had been marked as being skipped for a while. We weren't really sure why. We figured maybe because it's flaky. But then, as Joël had restored that test, he realized it was actually failing consistently. So it was a test that was failing for a reason folks maybe didn't understand, but they decided to cancel or to skip that test. But they didn't actually want to get rid of it because it seemed like a pretty important test based on the description. So Joël saw it and got excited because it seemed very relevant to some of the work he was already doing. So then, he is now investigating why this test is failing consistently. So in this story, we have four main characters: we have a class, two modules, and a class variable. So enter the class stage left. All right, so this class defines a class variable which I have to say is not something I work with very much in Ruby. So class variables kind of felt a bit novel and diving back into like, oh yeah, these are a thing. So the class defines a class variable that's called cache and assigns this variable to an instance of a cache. So then this class includes two modules who we'll call Module A and Module B. And we'll enter them stage right. And both of these models look to see if cache is already set. And if it's not, they also set the cache class variable. So with that information, in our test, we don't want to exercise the real cache just because then if other tests are reading from that cache, which is proving to be a source of flakiness for these tests, then they are overriding each other's expectations, and it's causing some of the tests to flake. So instead, we want to use a fake cache, just like an in-memory cache. So the test and its setup is already overriding. It's setting that class variable to say, hey, I want you to be a fake cache, just be in-memory. However, while executing that test, one of the modules is checking to see if that cache is set, which is being set in our test setup. So test setup sets the value. We're running the test but then in the module, the model checks to see if it's set, and it’s suddenly nil instead of using the cache that we had set. So now it's defaulting back to say, "Oh, it's unset. So let me go back and set it to the real cache," which is exactly what we're trying to avoid. So then the question became, if we're setting the class variable in our class, why is it being populated in one of the modules but it's not being populated in the other module? So one of them has it set to the in-memory cache, but the other one does not. So I'm going to gloss over some of the details because this stuff is pretty tangling. But essentially, when the test is running, and it's loading the class, and we are overriding that class variable, it's getting shared with one of the modules because as soon as one of the models does set that class variable, there's a bidirectional link that gets set between the parent class which is the module in this case, and the class itself. And as soon as that module sets the class variable, then they're going to talk to each other, and they're going to reference the same value. However, this only seems to happen for one of the parents. You can't do this for both. So if you have two parents that are trying to share a class variable with the same class, that doesn't work. So that's a particular bug that we were running into. I do have some good news because if anybody is very nervous about the situation that I'm describing, I feel you. The good news is that in Ruby 3, they actually warn when this is happening and have introduced an error. So you don't have this inheritance confusion that can come out of the fact that these parent classes are also trying to share a class variable with this child class. So in Ruby 3, if you are writing a class variable in that class but then you try to overwrite that class variable in the parent of that class or by the module that's being included, then an error is going to be raised. So it's going to warn you if you're creating this bidirectional link between those two class variables and that you shouldn't be overriding the child's ownership of that class variable. Instead, if you're going to use class variables, which, one, is not my cup of tea, but if you're going to use class variables, it should be defined in the parent class, and then it can be shared downstream in the inheritance versus trying to go upstream and then having your ancestors essentially override some of those class variables. So all of that is to say we were on a very interesting journey of understanding how class variables work, how the inheritance works, how that bidirectional link is getting established, and then how Ruby 3 comes in to warn us if something funky is happening. CHRIS: Oh, that is interesting. And I'm now going to catalog that as a piece of information that my brain will retain for roughly the amount of time that we are recording this podcast and then immediately forget. STEPH: As you should. [laughs] CHRIS: It's one of the reasons that I try to avoid inheritance. And I try to avoid class variables as much as possible because of this category of problem, a very subtle bug that you have to try and really hone in. And you have to be very smart to debug this sort of thing. I don't want to be that smart. I want to code in a way that I can be less smart on any given Thursday. That's my goal in life. I will ask one other question, though. So there's just a cache that this class and pair of modules are hanging around with, and then you want to swap it out for in-memory. This sounds remarkably like the Rails cache. Is this cache distinct special? Could it not just be backed by rails.cache, THE cache within the rails context, which can be backed by Memcached, or Redis, or in-memory when you're in tests, or the NullStore, which I think is the default in development is probably how that goes? Is there a particular reason? Is this a special cache? Is there additional behavior that this cache has beyond the normal thing? Or is it just like, at some point, someone's like, oh, I need a cache. I'm just going to use a class variable, that'll be easy, which it definitely is, but then you run into complexities. And caches are one of those hard things to get right. So it's one where I would immediately be like, whoa, whoa, I would love to not make up our own cache here. So I'm wondering, is there a distinct reason, or is it just this happened, and here we are? STEPH: So I think we are using a custom cache that we are pointing to. So it is another service. It's not a Rails cache or an abstraction that we can point to and use. It is a different cache that we are using. And I'm trying to think back to the exact code. But there is a method that essentially checks to say, hey, should I use the real cache? Should I use the in-memory cache? And that is something that we've explored to find a way to make this more global for the test suite because we really want to control this for all the tests. Because it's very easy to not realize in the test that you should avoid using that shared global cache. And so that way, the tests don't interact with each other but instead always use an individualized cache for each test to make sure that it is self-sufficient and independent. But we haven't gotten that far yet in figuring out how we can take a more global approach with this. CHRIS: Gotcha. So I don't know the details. I assume there are reasons here. But just to play this out, if we find ourselves saying we have a reason to have a distinct cache, to have a special cache over here, but it's a cache...and caches fundamentally, that word always will raise my attention. It will be like, okay, this is a place that bugs will come and aggregate. And we need a distinct one that has special behavior as an external service, or that is just something like in... There's a wonderful blog post that Mike Burns wrote at one point that was about...I think it was something like things that will make me look at your pull request in more detail. And I really loved it because it did capsulate all of these like, yeah, there are good reasons to do everything on this list. But if you do any of them, I will look at your pull requests and be like, oh, that's interesting. Why are we doing that, though? Do we have to do that? Are you sure? Are you triple sure we have to do that? And this is definitely one of those things where caches automatically catch my attention. Even if we're using the built-in cache, I'm like, do we need to? Is that a definite thing? And then all the more so when we're using a custom bespoke one. Again, I assume that there are reasons that there's something special that's going on here. Perhaps the caching behavior is distinct from just it's Redis, and we throw data. And if it falls out the backside, that's fine. Maybe you need entirely different behavior here. But it is something that I would poke at a bunch. STEPH: Yeah, you're asking a lot of good questions. I will have to go back and look at some of the code because we spent enough time in Ruby specifics that I didn't pay as much attention to the cache. Because right now, as we are working on these tests, we're trying to fix just the test without changing the application code, one, because that feels like a safer space. And if the test is flaky, we're just trying to change the test first. But some of these tests we're starting to realize I'm not sure we can fix the test without also changing some of the application code, or the way that we do have to fix the test is really an incentive to back up and say maybe now's the time that we look at some of the application code. Because another question that comes to mind is why use a class variable, and does this need to be shared by the class and the modules? And there's a part of me that suspects that maybe some of this logic was extracted to a module, but then it wasn't cleaned up in the other places. And so that's why we still have a reference. And it's essentially then being shared and set and unset and reset in those different places. So I think you ask some good questions, and I have some more questions of my own when we have time to revisit that portion of the test and application. As another example of some of the tests that I've been working on, one of the tests that I...because we have a list, we can usually tell some of the tests that are flaky. So one of the ones that I was investigating was a similar issue where there was a shared resource, and someone had tried to mock it out. So they had taken the time to say, hey, I don't actually want to use that real resource that's over there; instead, I want to just return the scanned value. But instead, they'd accidentally stubbed out a class-level method instead of the instance-level method. And so it was running, but it wasn't actually stubbing anything else since that's the method that's not getting called. So that was just an oversight for that test. So I fixed that test. But I noticed that we were using allow any instance of, so then I did take the time to go through that file and change and move away from the use of allow any instance of. And for folks that are less familiar with allow any instance of, RSpec has some really great docs that talk about how it's very helpful for dealing with legacy code. But essentially, it is a code smell that you're using; allow any instance of because you are saying that my test is or my code is so complex that I can't really mock out the specific instances that I want to and then return specific behavior. So instead, I'm having to use this more global approach to say, hey, any instance of this method, I want you to mock it out versus this very specific instance that I know that I'm working with. But we can include a link in the show notes because there's a nice write-up that talks about some of the reasons that allow any instance of is not recommended. So that's been kind of fun. There's been a little bit of joy to get to refactor away from that and actually stub out a specific instance. Part of the work, too, that I'm noticing as Joël and I are going through these tests is leaving breadcrumbs for other developers as well because they have a very large team. And they're very junior friendly, which is just incredible. I love that so much about this company. And because they do hire a lot of juniors, then it is a tough codebase. It's a fairly old codebase. So as these juniors are coming in, they're seeing a lot of these patterns. And they're propagating these old patterns that aren't necessarily the best patterns to propagate. But they're doing their best, and then they are reusing what they're seeing. So part of the work as we are revising these tests, my hope is that people will see some of these newer patterns and use those instead of following some of the older patterns. CHRIS: I can only imagine that you're writing borderline novels in your pull request descriptions and commit messages there. I do wonder, is there an index of those that you're collecting? So there's like, here's the test remediation examples list, and you're slowly adding to them. This was a weird one with a class variable. And this was a weird one that had flakiness due to waiting or asynchronous behavior. And gathering examples of those, but specifically from the codebase. I could see that being a really useful artifact because I happily traverse through git blame all the time. But I don't know that that's always a thing. And frankly, I have to work for it sometimes. So if there is that list of here are pull requests that specifically did X, Y, and Z, I think that could be super useful. STEPH: Yeah, that's a great idea. And yes, they have some shared team documentation that speaks to specifically flaky tests because they're aware that this is a problem. They are working together to address this. And they have documentation that states ways to avoid flaky tests. If you encounter a flaky test, here are some of the ways that you can triage to find out what's wrong. So as Joël and I have been finding good examples, then we've been contributing to that document. And they also have team meetings. So our plan is to attend some of those meetings and be like, "Hey, this is just some of the stuff that we've seen this week, some of the things that we improved and changed," and share the progress that we're making. Since everyone is aware that there are these developers that are working hard to improve the test suite, but then share that information with the rest of the team so they too can feel...one, they can just see the changes that are taking place. But they too can also benefit and apply those strategies themselves when they see a flaky test. Oh, but you did just remind me of a thing. So one of the tests that I was going through...I'm very intentionally going through and making the smallest change possible. So I will do the gross, ugly fix whatever it is to get something to pass, and then I will commit it. And then I'll think about okay, well, how can I make this better? So essentially, I have the fix, whether it's pretty or not. And then, after that, I start to have other commits that make it prettier. And so, I had a pull request that had four commits that told the story that I was very happy about and progressed along in a more positive direction. And I issued that, and I discovered that Gerrit, when it sees four commits, it split all of them into their own change request. And so, instead of having what I thought would be this nice story, now got split across these four change requests. And I thought, well, that's less helpful. So I ended up squashing two of them, but I still kept three of them because they stood alone, and each told a story. But that's something that I've learned about Gerrit. CHRIS: Always so interesting how our tools shape our work. STEPH: And it made me think back to the listener who asked the question about ensuring that CI runs for each commit. Well, here you go, Gerrit. [chuckles] Gerrit does it for you. It ensures that every commit gets split into its own change request. CHRIS: I mean, as you said earlier, not my cup of tea but... [laughs] STEPH: Yeah, I'm still lukewarm. I'm still discovering Gerrit and how we get along. 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. What else is going on in your world? CHRIS: In my world, we keep adding new users to the system. We keep doing more stuff. These are all wonderful things, the direction you certainly want to be heading. But as we're doing that, I've recognized that we had a lack of process and a lack of formalization of certain things. And a lot of the noise of the work was just coming to me because I was the person that everybody knew. I can ask a question; Chris will know the answer, et cetera. And then there were things that we needed to keep an eye on. But because it was everyone's job, it was no one's job. So we've introduced the idea of a point person on the engineering team. So this is a role that will rotate each week. I think you and I have worked on a handful of projects that had something similar to this. There was a team that we worked with that had an ad hoc list, which were just little tasks that needed to be done by developers. So there was one person who would run with that. I've heard it called captain before, the sprint captain. We're not really doing sprints. So for various reasons, that title didn't work for me. But point person is what I went with here. And so the idea is rather than having product management or anyone else in the organization just individually reaching out to developers, we want to try and choke that off, have a single point of communication. And so just today, I introduced into Slack, a group, but it's a group of one person. So @pointdev is technically the handle for this person. It’s a group in Slack. And each week, we'll rotate who the members of that team are. And technically, you could add multiple, but the idea is this is just one person. So we'll rotate the person. And what ends up happening is if anyone...say the product manager says, "@pointdev, what's the status on..." blah, blah, blah, that will notify the person who is the point person that week. So that's a nice feature in Slack so that we can condense it down and say rather than asking individuals, ask this alias. We're introducing one layer of abstraction in our communication tools, much like we do in our software. So I'm drafting now the list of like, here's all the stuff that I think this person...because we're trying to push all of the quote, unquote, "other work" the non-product feature development work into this person's purview for a given week. So it's monitor Sentry for any new errors as they come up, triage them, and figure out what we want to do. Ideally, and this is perhaps aspirational, I would like to keep inbox zero in Sentry. I know how you feel about that more generally and perhaps even more specifically within the world of errors, but that's my dream. We're going to see how it goes. STEPH: I don't know if people know I am the opposite of inbox zero. This is the life that I'm living. CHRIS: What about with errors, though? What about something like Sentry? STEPH: I want to say that I would be a better human with my email. But I'm going, to be honest [laughs] and say that I would probably have the same approach where I am not an inbox zero person. I've come to terms with it. I used to really strive and think I needed to change. But I have reached a point of comfort with this is who I am. There are many like us, so shout out to all y'all. CHRIS: Oh yeah, by far the more common approach, I think. So specifically with the errors, I struggle a bit with it because what ends up happening is we are implicitly ignoring the errors. And if we're doing that, I would rather just sit around and have a conversation and be like, let's just explicitly ignore them. There's a button in the UI. We can ignore them. If this is not a real error, we can add it to the list of things that we do not report on. We can ignore that error. We can ignore it for a week and add a card to Trello that has a due date that says, "Hey, we got to work on this." But let's take that implicit indifference to that particular error mode of our application and make it explicit. Let's draw that line in the sand such that when I see a new error pop up, I'm like, oh, that seems like something I should do something about. I really want high signal-to-noise when I'm seeing errors coming. And so I'm willing to work for that. But it is a trade-off, and it does take effort. And it's noisy, especially browser extensions, and whatnot, just fighting the page. Facebook showed up one day. I don't know how Facebook got in there. Someone was browsing our website from within Facebook's browser, which I didn't know was a thing, but they had their own thing. And it fires a bunch of events, and Sentry was just like, let me slurp all of those up. Those seem fun. That was noisy. So we had to turn those off, but we explicitly turned them off. STEPH: I do like the approach that you're taking where it's one person, and then it's a rotating shift because I think that makes it more reasonable for someone's who's like, hey, this is going to be noisy for a week. And then you're going to look through these emails and check all these errors, and then either silence them because you don't think that they're interesting or mute them for now. Or if you're going to convert it into a ticket, set a due date, whatever the triage approach is going to be. But that feels more achievable versus inbox zero for life is just exhausting. But I feel like if you're doing it rotating week by week, that seems like a nice approach and also easier to keep it at inbox zero because that way, you are keeping up with all the errors. Because I agree; otherwise, what's the point of tracking all the errors if you're just going to ignore them? CHRIS: Yeah, definitely the rotating, I think, is critical. I think the other thing that's been critical specifically on the error front is we've had now a handful of meetings where we triage the backlog together, the backlog of errors. So like, what all is coming into Sentry? What's going on? And we go through the process of determining is this a real thing? Should we fix this? Should we ignore it? And we do that together so that it becomes not just one person's intuition about whether or not this is important or not or what the source of it might be but a shared intuition such that now any one of us, when it's our week, can ideally represent the team in that way and be like, never mind, never tell us about this again because it's very easy to silence things in Sentry that you would actually like to know about when they become real. But right now, we have this edge case that is an ignorable version. So trying to get there that's been fun. But yeah, once again, Sentry, that's one of the things on this person's list. There are ad hoc support tickets for our operations team. So anything that needs to happen on a user's behalf that currently needs a developer to console, let's funnel all of those to this one individual, respond to any new questions. So this is where that Slack handle will be useful. Check for any stuck jobs in Sidekiq. So is there anything that's been retrying for a while? Because it probably shouldn't. Maybe one or two retries is cool, but past that, something has gone wrong. And we should either get in there and fix it or just kill that job because it's never going to succeed, which is quite often the case but go in there and keep an eye on those and then look for anything. We're starting to use due dates within Trello, which is currently our project management system. We'll see. Someday we're definitely going to grow out of that. But for now, it's good enough and checking for anything that's overdue or coming up in the next week in terms of due dates and just making sure that we're being responsive to that. And so, I really like the idea of having this be a named set of things and a singular focus for one individual. Because again, that idea of like, if it's everybody's job, it's nobody's job. Or if it's nobody's job, then it's my job, and I don't want it to exclusively be my job. [chuckles] So I'm trying to make it not exclusively my job and to share the knowledge about it and make sure that these are skills that we all have and ideas and et cetera. But also, I would be fine to answer fewer questions in Slack each day. STEPH: I have to admit, as soon as you were telling me that you had established this role, I was quietly congratulating you on helping delegate some of these responsibilities to the team. Because like you said, you are then the person that takes on all these tasks. CHRIS: There's a laziness to that. Like, it's easy for me to just answer the questions. It's harder for me to put up a wall and say, "No, no, we have a process for this." And quite possibly, what's going to happen behind the scenes is that questions are going to come in to whoever is this point person. They're not going to know the answer. They're going to reach out to me, and then that conversation is still going to happen. But even by doing that now, now that person will see that answer, will understand the thinking or the background, the context that I have. And so it's that weird thing of like, it would be so much easier for me to just answer one question. But to answer all the questions, well, I can't do that. And so I'm working to try and do more of the delegation to try and hand things off when they're in a known state and to identify this sort of stuff so that the team broadly can be stronger and better able to support everyone else in the organization. So that's the dream. We'll see how it goes. STEPH: Yeah, I love that approach. I'm also thinking how interesting this role is because I'm imagining a mix between someone who is like the front point person at like an ER. So like, things are coming in, and they're in a tragic state and need help and need to be diagnosed. But at the same time, you mentioned they're going around. They're checking Sidekiq. They're looking at some email errors. So they're also that night shift guard that's walking around with a flashlight just poking in each room. So it seems like a very stressful and low-key role all at the same time, all mixed up into one week. That person probably needs a beer at the end of the week. CHRIS: There is a version of the story in my head that is...I wouldn't say this feels like a failure mode, but I would rather this not have to exist at all. I would rather things to be calmly humming along and not require a dedicated person each week to deal with the noise. I don't think that's realistic, certainly not as early on as we are in our organization. But I do wonder, is this a crutch? Is this something that we should be paying more attention to? And I know in teams that you and I have worked with in the past that has been a recognition of like, this is a crutch. But it's a costly crutch. Like, we're taking an entire...in our case, it's not requiring the entirety of a developer's week. They're able to do this pretty easily and then still get a bunch...like, 75% of their time is still feature work. But we're just choking down who's the person that will be responding to questions when they pop up so that fewer individuals are interrupted? But I have seen organizations where this definitely filled an entire week and spilled out more than. And then there was the recognition of that and the addition of another person that comes along and tries to fix stuff along the way as opposed to just responding. And so I want to make sure this isn't a band-aid but is, in fact, a necessary layer that we then try and shore up, you know, we should have fewer errors. That feels true. Okay, cool. Let's fix the bugs in the app. And these ad hoc things that an admin needs to have done can that be a button in the UI? Can they actually self-serve in those cases? And we're slowly moving towards those. Ideally, fewer jobs get stuck in Sidekiq. And so, my hope is that this isn't a job that gets harder and harder over time. It's a job that potentially, if we're being honest, probably stays about this hard. I don't think it's ever going to be just like, nope, nobody needs to do anything. The app just runs, and it's great. And it never has bugs. But that is a question in my mind as I start to embrace this thing of like one person is dedicated for a week to this. And if right now it's only 25% of their time, okay, that's probably fine. But if suddenly it's 50% of their time or 75% or 100% of their time for that whole week, that becomes too high of a bar in my mind. And I want to keep a close eye on it and make sure it's not trending in that direction. And I will be one of the people on the rotation. So I'll get to be in the trenches. STEPH: I appreciate all the thoughtfulness that you're putting into it. And I'm thinking back on a project where we had a similar rotation because we had an issue Slack channel. And so anytime there was an issue, then it would get posted in there. And before, it was going out to everyone, or there was one particular person that was always picking it up and then trying to delegate it to others as they needed to. But then we started a similar rotation. And one of the key benefits that I found from that is it signaled to the team, hey, this person might get pulled away. They can pick another ticket or two, but we need to give them lower priority tickets because there's a chance that they're going to get pulled away to work on something else. And that's okay, and we're going to plan for it. Versus without this role in mind, then you had people all taking on high priority tickets, but then someone had to be the one that's like, well, I'm going to punt on my high priority and feel stressed about the fact that I've got this other thing to deal with. But then, I didn't actually do the work that I planned for. So I feel like you're helping introduce calmness into the week, even if it is a stressful role. But then there's the goal that this becomes less of a stressful role, and if you see it trending in the opposite direction, then that's something to investigate. But I also feel like triage and communication is such an important part of being a developer that it also feels very relevant upskilling for the whole team to go through. So there's also that benefit of where this approach also empowers the rest of the team to also experiences, build empathy, look for additional fixes, and then also build these important skills. Overall, I really applaud your thoughtfulness. And I think it's a really good idea. And it will be interesting to see which direction that this role trends if it gets easier or if it's getting harder over time. CHRIS: Well, thanks. I appreciate that. And I'll certainly report back as we develop this but hopefully, it stays about where it is. That feels right. And I think I'll probably...that's one of those things that I will monitor. And if I feel it moving in the wrong direction, then step in and try and get it back to this space because this feels like a maintainable reasonable amount. And we shouldn't be fixing every bug and adding every button to the UI. That's just actually not how it works, unfortunately, would love to. That's not true. You shouldn't have every button in the UI. That's so many buttons. But broadly, I hope we can maintain roughly this, and I think identifying it and laying it out now I'm feeling good about having that structure. So yeah, we'll see how it goes. Will report back. But again, thank you for the kind words. With that tour of a bunch of different things, 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 people 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.Sponsored By:Scout: Scout APM is leading-edge application performance monitoring 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 performance abnormalities -- like N+1 queries, slow database queries, memory bloat, and 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 worldwide call Scout their best friend and try our error monitoring and APM free for 14-days, no credit card needed! And as an added bonus for Bikeshed listeners: Scout will donate $5 to the open-source project of your choice when you deploy. Learn more at scoutapm.com/bikeshed.Support The Bike Shed
undefined
Dec 21, 2021 • 34min

320: Remember The Fun: 2021 Recap

Steph and Chris recap their favorite things of 2019 and 2020 and share their 2021 list. Happy Holidays, y'all! Steph: Feature flags and calm deploys Creating observable systems Debugging Working in seasons Don't forget the fun “The longer I’m in the software game, the more I want things to be calm” - Steph Chris: Pushing logic back to the server Svelte Remote work (but maybe hybrid!) Vim Joining a startup as CTO This episode is brought to you by ScoutAPM. Give Scout a try for free today and Scout will donate $5 to the open source project of your choice when you deploy. Listen to episodes from 2020 and 2019 👇 Episode 274 - Top 10 of 2020 Episode 273: Retro on Top 10 of 2019 Become a Sponsor of The Bike Shed! Transcript: STEPH: Are we taking off the next few weeks? CHRIS: According to Steph's schedule I think we are. STEPH: You know, that's Steph and her schedules. 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. Hey, Chris, what's new in your world? CHRIS: Well, this will be our last episode for 2021. So that's new collectively in all of our worlds, I think, which is exciting. We'll be taking off the next few weeks for the holidays. But as has become tradition, I think it is time for you and I to review some top 10 lists from last year or two top 5 lists, and then maybe you share some new favorite things. How does that sound? STEPH: Yeah, I'm excited. I love that we take this time to reflect about what we enjoyed about the past year and share our top things. It's like Oprah's list. You know Oprah has her list of favorite things, and we have our list of favorite things. CHRIS: It is almost exactly like Oprah. STEPH: It feels a bit blasphemous to compare our list to Oprah's list but here we are. [laughs] CHRIS: I tried to give the hyperbolic sarcasm there to be like, and let us be respectful of...but yes. STEPH: Good. You got it. [laughs] So to prep for sharing our new list of favorite things, do you want to start by going through the list of favorite things from last year? CHRIS: Sure. And just as a reminder, if anyone does want to listen to the episode and hear a bit more detail about our thinking on these, we covered this in Episode 274. But for me, the 5 items that I covered last year were Tailwind CSS. So the utility-first CSS framework which I continue to love and use on every project that I possibly can. Remote work, that was a relatively new and novel thing for me at that point. Similarly, I have continued on with that and if anything, leaned into it all the more. Next up is Svelte. Svelte is a JavaScript framework that I have grown to love even more over the past year. Spoiler alert, that may show up later in the episode. Next up, we had Postgres, PostgreSQL, the database engine that is wonderful, and I had spent a lot of time with last year. Frankly, I haven't spent as much time with it this year but it’s still something that's near and dear to my heart. And the last was Inertia.js, a framework that although it's got js in the name, it's both server-side and client-side and binds it together and gives a wonderful experience. I believe I've talked enough about that throughout the rest of this year that perhaps you've heard me mention it in a previous episode, listener. But yeah, that was my top 5 for 2020. What about you, Steph? STEPH: All right, so the things that I had from last year are one-on-ones. I don't remember exactly what I said about them, but I am still a fan. I still very much enjoy them. I learned a ton from them either participating or leading them. Rails, also still a fan. Async communication, yes, love it. It really helps more people be involved in the conversation when it's async communication. feature flags, also still a fan. And Elixir and Phoenix is on the list also, still a fan although frankly, haven't done as much with it. CHRIS: So, Steph, I have a question for you. Actually in preparing for this episode, I re-listened to Episode 274, which had our top 10 list for 2020. And then I also listened to 273, which was the previous episode which had our retrospective on the list from 2019. So at this point, I've now reviewed all of these lists, which is now 10 items, and 10 items for each of us. And what was interesting to me, at least from my side, and especially as I was preparing for this year, is stuff's mostly stayed the same. I kind of still like most of the items on the list. And certainly, nothing has changed in a deep way where I'm like, you know, I used to really like this, but I don't like it at all anymore. So I'm wondering, is that the same for you? Is there anything that you've changed your mind on amongst this set of items? STEPH: Looking at the list, I still really like everything on the list. So there's nothing that I've changed my mind about significantly. I'm realizing as we're creating this list each year, it's likely a list that I'm going to continue to grow and add to instead of subtract from. Most of the stuff, I guess because we have a full year by the time we get to this point, I feel pretty good that this is something that I like in the world versus something that may be more of a month to month experiment that then I'd change my mind on. So everything on the list still rings true for me. And I have some new stuff that I'm going to add to that list. CHRIS: Ooh, new stuff, exciting. Yes, this is what we're here for. So, Steph, let's dive in. What do you got? STEPH: So in preparation for this episode, I started thinking through all the different ideas that I wanted to add to my list and all the topics I'm excited about. And I started to wonder what are the things that we really said? What can data tell us about these episodes versus just trying to think through my feelings of the past 12 months? Because it's very easy that I forget things that were important to me at the moment. So I started wondering, what data could I collect from the different episodes? And now that we have transcripts that started back in I think around May of this year, I built a small little Ruby program to perform a word frequency analysis and generate a very low version of a word cloud. But I wanted to find what are some of the top things that we said? And it came out rather poetic. And I tried to ignore some of the small words just prepositions, and a, and the, and things like that were that were less interesting. So here I've got a couple of different lists, a couple of different facts that we can explore. So here are the top 10 words that we said. So there's code, great, write, feature, question, idea, interesting, love, no, and laughs. CHRIS: Laughs is in parentheses or brackets to say this is where they're laughing? STEPH: Exactly. CHRIS: Wow. A, that feels true. B, that's just delightful. And I'm so glad that you did this. For anyone listening at home, this is a complete surprise to me too. So I'm really enjoying going on this ride. But yeah, that feels like a representative list. STEPH: There's another poetic one because then I started looking at some of the episodes individually as I was building this out to handle all the episodes. This is over 28 episodes. And so I pulled a specific episode with Joël Quenneville where we talked a lot about debugging. And so the top words from that episode are debugging, people, think, don't, love, time, bug. And it's fun no matter how you hear that or read that you get something new out of it each time. And now I'm really into this word frequency art or whatever it is that we're going to call it. CHRIS: That's fantastic that I want a little bumper sticker of that amongst the bumper stickers that I've claimed I want from things we say on the show. I want that one with Joël's face on it right there. That seems like a perfect item. STEPH: So I also tried to figure out how many times we said it depends. And that one got a little trickier, and I was also surprised. But according to the data, we've said it depends around 10 times. And I feel like that's low. CHRIS: That feels very low, huh. STEPH: It does. I agree. That one feels a bit low. And so those were the fun, more poetic like, what are the top things that we said? And then I started looking for more what are the technical things that we talked about, some of the different frameworks or languages? So I started looking specifically for those. So over these 28 episodes, we said Rails 200 times, which is a lot. [laughs] CHRIS: Good job, Rails. Way to show up on the leaderboard. STEPH: And then next in that list data, some form of test, tests, or testing. We said around 230 times database. Ruby's next on the list at 140, then Sidekiq, retro. Monitoring is a big one. JavaScript, agile, REST. React, React is at 52. I was intrigued that React was spoken as much because I know I haven't worked in React in a long time. So I'm going to give you credit for that one. Manager, Svelte, Svelte, and Inertia are both around 45, 40 times that they were spoken. Python, Postgres, Rust, Elixir, Elm, Vim, and tmux. CHRIS: Wow. I like that list. STEPH: One other fun data point is that we said the word hard 20 times more than the word easy. CHRIS: That feels fitting. STEPH: It does, right? CHRIS: I love this work, but it's not easy. STEPH: Yeah, I appreciated that. I was like, that's true. CHRIS: [chuckles] STEPH: So that was some fun with words and frequency analysis, and it was neat. So I'm excited to do this for more episodes and to do it per episode because it highlights some interesting themes for the episode. So pulling just from the data, then I'd say the top things from my list are Rails, data, testing, Ruby, Sidekiq, and retro. Those are the top things. But I'm still going to be creative with it and add to the list the things that I want to include on there. So the first one this one is a bit of a repeat, so that's why I'm going to bring it upfront. But it's feature flags and calm deploys. That is something I am still a big fan of that I really appreciate. It can lead to some slightly increased tedious workflows depending on how diligent you are in feature flagging your work and keeping new work behind that gate so then you can turn it on when you want to. Also, the data supports it. We said flag like 67 times over 28 episodes. And I'm betting that was coupled with feature flags. So I feel pretty good about that one. CHRIS: I think half of them were probably flag football is my guess if I remember what we talked about. STEPH: We do play a lot of flag football, uh-huh. CHRIS: It's interesting that you're leading with that. So one of the other items that I pulled out as I was reviewing the previous episodes was a quote that you made that resonated deeply with me in that moment and all the more so now. And everything I think about software probably falls a little bit under this bucket, which is...this is the quote from you, "The longer I'm in the software game, the more I want things to be calm." And I think my response in the moment, which is why this was primed in my head, was I want a bumper sticker of that. I want it on a t-shirt or get a tattoo of it. [laughs] And I stand by those words because that's a beautiful sentiment and definitely, for me, speaks to a lot of the work that I want to do and how I think about what I put importance on. STEPH: Thanks. Yeah, I find it makes a really big difference in terms of the quality of the work and then also, the happiness of the team. How about you, what's first on your list? CHRIS: First on my list this year is going to be...it's a little bit of an abstract concept. So we'll see how well I can define it in a small amount of time. But the phrase in my mind is pushing logic back to the server. Over the past many years, let's call it like a decade or so, I've seen this gradual shift where more and more logic is being implemented client-side. And client-side can mean a bunch of things. It can mean a JavaScript client that gets downloaded and then runs. It has lots of smarts in it and knows about all the business logic but also iOS apps, Android apps, et cetera. And every context that I've worked on that I felt the pain of now we've got our business logic distributed across all these different systems. I've seen some really interesting approaches to try and bundle up the logic and use it in a shared library. Perhaps in JavaScript, I've even seen some other approaches where this is a bundled C++ library that we somehow embed in every context that we want to run. And that's where the business logic is. But fundamentally, I felt a ton of pain from that. And I've always had this idea in the back of my head that wherever possible, I like to pull logic back to the server because the server is this safe space with all the knowledge that I want in the world. And I can have secret environment variables, and I can add the database. And I can combine different sets of data very easily. And I can have the logic implemented in a single place. And that's wonderful. And more and more, I've started to pursue this. Some of my work with GraphQL was an attempt to get this because a REST API is just like, here's a bunch of data. Combine it how you will. Have fun, front end. Whereas the GraphQL API starts to be more about the relationships between the data and the connections. And you can ask more interesting questions of a GraphQL API in my mind and ideally then push some of that logic back to the server because the GraphQL API encodes it in relationships and whatnot. But probably the thing that has helped me the most on this is Inertia.js which was on my list last year. It remains something that, if anything, I tripled down on my enjoyment of Inertia.js. But it allows me to continue building my logic such that it's on the server-side. And I don't need to implement a client that knows hey when a user adds an item to their cart, I also need to update that little icon in the top-right corner. I don't even need to think about that because Inertia uses the traditional request-response lifecycle, but then handles it in a smart, forward-thinking possibly animated way. And I'm just very happy with that and all of the explorations that I've had around pushing logic back to the server. And actually, as I explore this even a little bit more, at my company, we're now starting to explore building native mobile apps. And we're trying to figure out what that means for us as I try and cling desperately to this idea of pushing logic back to the server. So that'll be a topic that I would love to chat with you more about in future episodes. But I think I found a way to, as I said, cling to this idea of pushing logic back to the server. So yeah, that is item number 1 for me. STEPH: I'm very excited for those future conversations. You reminded me of something that I've heard from someone else at thoughtbot. I believe it's Stephen Lindbergh that said this. He was giving a presentation talking about forms. And one of the things he said was, "Stop using client-side form validations." And that's a bit of a blanket statement. And there are always some caveats with those statements. But when he said that, I thought, yeah, that sounds great because you have to validate it on the back end anyways. Let me rephrase that, you should validate it on the back end. A lot of applications don't. CHRIS: I would go with have to just some opt to not despite the fact that they definitely have to. STEPH: That's true. I just wanted to fuss at the people who aren't doing it. [laughs] CHRIS: Steph's getting to fussing. STEPH: And I just really liked what he said because I understand why people started adding more client-side validations because then they think well, this creates a better experience for the user. We can give them faster feedback. But if you get to the point that you're actually hindering their experience...like if you've been filling out a form and it's telling you that you're incorrect, and it's because you haven't met the specific regex they're looking for, that annoying behavior that you see on forms that's often a result that I see from client-side form validations. Also, if you're at the point that you're using form validations to drive the user to do the next thing, there's a good chance that form is too big. And there's an opportunity to break that up into a smaller workflow. So that way, you're not using validations to essentially coerce or force a user into a particular path and use more helpful ways to help guide them through that process. So I'm very excited for our future conversations about pushing more things to the server. And side note, stop using client-side form validations or just reduce it. Dial it down. Don't dial it up, dial it down. CHRIS: Oh yeah. That is such a great example of this theme. And again, hopefully, we'll chat more about this in future episodes. But yeah, so that's item number 1 for me. What is item number 2 on your list? STEPH: So this one I really want to say thanks to you because I feel like you've brought a lot of topics and conversation about this particular idea to the show. And that has really resonated with me and influenced me as I've joined different projects that either have observable systems. And then that has been really helpful as then we are jumping into the project and debugging and then contributing to that system or where they're lacking that observability. And that just makes work and life so much harder. So thank you to you and everyone else that has contributed in having conversations about observable systems on the show. Specifically, I'm thinking of the episode with Charity Majors where she talks about observable systems. And so that is number 2 on my list. CHRIS: Oh yeah. I do love some observability. It's one of those ideas that once you get it in your head, you can't shake it. You can't unsee that you can't see what's going on in your runtime system. I will say the app that we're building, the core Rails application, we've instrumented it heavily because we're trying to get in early on the observability game. But now we can see everything. And we've yet to really get to that deep understanding of like, that's just noise. We don't need to care about it. So let's silence those. Let's dial these up. These should go piped into Slack and how to sort of triage that. So right now, it is a bit noisy in our world. I'd rather that than the silence, than the crickets of I don't know, something happened. There is a form validation, but it seems fine. It's happened a lot since the last deploy, but that seems fine. I'm trying to avoid that kind of stuff. But as a result, sort of the rough edges of the early times in observability, but yeah, huge fan of that. Glad that that made it onto your list. For number 2 for me, this is a recurring theme from last year, but I've doubled if not tripled down on it. So this will be Svelte, Svelte the JavaScript framework that is just so fantastic. The more time I spend with it, the happier I am that I've leaned into it. I took I would say a tiny bit of a gamble in choosing it for the view layer for the application that we're building. It's not as popular. It doesn't have nearly as much community, mindshare, shared libraries, et cetera, et cetera. But A, because we're working with Inertia, Svelte occupies a smaller portion of our application architecture. So that made me feel more comfortable with that decision. And I liked a lot of the fundamentals that I saw on the Svelte community. And over the past year, I've just seen each of those get reinforced. Svelte wonderfully leads with accessibility as a primary concern. And one of the things that I see is although there are fewer packages out there in the Svelte ecosystem, the ones that there are very often like, and of course, we thought about accessibility, and screen readers, and keyboard navigation, and all of that. And so you don't even need to worry about that. It's like, thank you. That is wonderful. Likewise, SvelteKit is a project that came out. I believe it was released, and I think it's 1.0 now or at least it's on its way to 1.0 now. And it's starting to get real usage. And that's a Next.js-like framework that takes your Svelte application and allows you to build it, run it, compile it. You can use it for packages. You can use it for apps. Wonderful stuff in there. And it's a great answer to how do I actually build a Svelte app or a Svelte package? Likewise, Rich Harris recently moved to Vercel. Vercel is one of the big names in this world of we're building fancy applications on the internet. And so that's a huge vote of confidence for the framework. And now Rich Harris the creator of Svelte will be working on it full time. So it's just a bunch of signals that are pointing at although it's still definitely not nearly as popular as even Vue or certainly not React, Svelte is a wonderful choice. And I have enjoyed every minute that I've worked with it. STEPH: I like how you're doubling or tripling down on Svelte. I've heard so many wonderful things about it. I feel like I should be a pro at Svelte at this point from everything that you have shared and brought to the show. But I'm still looking for that opportunity to get to test it out. So I'm excited to hear more about it next year. 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. So third on my list, this one is more...it's something that I'm toying around with. I don't really have any concrete answers around how it's going to look but something that I'm interested in exploring further. Based on earlier this year, I took a month's sabbatical and that was phenomenal. I felt like this incredible reset, and then I came back more energized and interested in my work. And also, I got to explore other facets of life that I just normally didn't have time for. So number 3 on my list is the idea of working in seasons where you are focused and work really hard on a project. And then let's say you take a couple of weeks off in between, and then you go on to your next thing. But I like this idea of chunking my work time because I found I'm very much a person that I'm on or I'm off. And it's very hard to create that balance between those two parts of myself. And this may be a nice way to do it to say, I'm committed. I'm doing this for six months. But then I know I'm going to book a vacation, and I'm going to take a solid two weeks off or maybe even a solid three if that's something that my work and time allows. But I'm very interested in that idea. I think it came from a conversation with someone else about academia life and how that is an approach they take where they work in those seasons where they work for the academic year, but then they take a summer off, and then they go back to work. And I very much like that idea and that approach to work. CHRIS: This is such an interesting topic in my mind. I grew up both of my parents were teachers. So for the entirety of my life, I got summer vacation and my friends got summer vacation, and my parents got summer vacation. So clearly, everyone in the world got summer vacation. This is just a true thing about the universe. And then spoiler alert, I learned the truth; it is different out there. So that took some getting used to. And then I have done an absolutely terrible job of this. This is an idea of like, I believe in this idea, the phrase that you used of living in seasons. It makes so much sense to me and seems like such a useful way to be. But I have at most taken two weeks off at any given point in my working career since I graduated college, and that was for my wedding. And that was it. And between jobs, one time I left work like 15 minutes early on Friday, and then I started the next job on Monday. That was one of them. And then I did take a week off between my most recent job switch, just a whole week. Well, actually, that's not true because we recorded The Bike Shed in the middle of it, and I took a bunch of meetings to be ready to start. I'm terrible at this. Even though it's an idea that I believe in, that I want, I have never pursued this in a deep way. And it's something that I would really love to do. But yeah, I've not really done it. So you mentioned academia and so there's the natural cadence to a year. But there are also sabbaticals. That's a thing that exists in the world. It's an idea that's already out there. Once every seven years, you get to take six months off just to go on an adventure. That sounds fantastic. I would like that, please. So I got to make that work in the world somehow, probably not for a couple of weeks, though, because I'm in an early-stage startup at this point. And so I probably got to hang out for a little while and get some stuff done. STEPH: I like how you pointed out that sabbaticals exist; those are a thing. You also mentioned that a lot of times, maybe there's seven years or five years is what I've seen at companies before you get a month off. And while that is wonderful and much appreciated, I am interested in finding a way to include sabbaticals or at least those breaks more often in my life. Because I know I'm someone that I'm going to be focused on, and I'm going to work hard. And rather than just continue to do that and then one day burn myself out, find ways that I can have more of a structured this is when I'm on. This is what I do. It's what I'm interested in. I'm excited about this. But now that I'm done with this after six months, let me go take a solid two, three weeks off to reset, recharge, find some other hobbies, and then come back to this. And I think that will make for a much longer and happier career. So I haven't worked out the details, but it is something that's on my mind. So that is why it is my number 3. What's your number 3? CHRIS: My number 3 is perhaps in a similar space. And again, this is another one that was on my list last year, but I've leaned into it all the more, and that's remote, working remotely, working from home, et cetera. I have embraced it all the more this year. The new company that I've joined we are a remote-first company. And so that is the mode that we're going to be working in. And that was something that I certainly pushed for because I feel like it is meaningful across the board. And if you're intentional about it from the beginning and think about things like async communication, and how do we handle this, that's all the more meaningful. But also as vaccines and things like that have become available in the world, last year, remote was just the thing that we did. And this year, it was more of a choice and also was offset by the occasional in-person meeting. So the other folks that are in the company currently are co-located around Boston as well. So we've had a number of days where we'll go downtown meet at a WeWork or some other shared co-working space. And we can have the occasional bit of in-person time. But we try and be very intentional with that. We try and make sure that when we're going to do that we have an agenda, even if that agenda is just connecting and socialization, which I think is deeply important. And that is incredibly hard to do just over Skype or Zoom or any of those tools. But then the vast majority of the time I get to not have a commute. I get to work out more easily. I can cook dinner more easily. I can go for a longer walk with my dog. All of these things are just options now that are so, so meaningful and allow me to have a slightly calmer cadence to my life which is a thing that I want both in the work and in the life. So I'm all for remote and perhaps tinged with a little bit of hybrid in person, kind of figure out how to get that right optimization. But yeah, big fan and will be continuing to do it with the caveat, and this is something we talked about the previous time we talked about it. This makes a lot of sense for a certain point in your career. I still wonder about how to make this work for folks that are newer to the industry. Junior developers joining a team being remote feels like it would be very complicated. So at a minimum, needing to be incredibly intentional around that. But also, is that even the right answer in that case? I don't know. STEPH: I have feelings about that one. But I'm going to punt for now for another episode because I think that's a really great topic to dive into. And yeah, we should talk about that more. CHRIS: I look forward to that conversation. But yeah, remote, that is my number 3. And with that, I will send it back to you for your number 4. STEPH: I love that one. I'm a big fan of remote work. All right, for number 4 it's debugging. So I feel like we've had a number of conversations. Joël Quenneville has been on the show to talk about debugging and debugging not just for the art of it and the necessity of it but really building concrete skills around how to debug and then finding ways to share that information with others is really powerful. And I feel like it's something that a lot of people just pick up on the job as you go, which is great. But it'd be great if we could create shortcuts for people. So then that way, they can have that information sooner rather than just waiting for a painful experience and then happen to pick up new tools for debugging. So debugging is a big one for me. I also think that's representative of the type of projects that I've been on this year where a lot of them have been more triage-focused and how important debugging skills are in that moment, which I'm sure is also why observable systems is on the list. So for my number 4 is debugging. And we'll link to Joël's episode about debugging because it's delightful. CHRIS: Debugging, one of the most pointed examples of alchemy in our work is the intersection of art and science and craft and all of that. And yes, debugging, what a fun topic. But for my number 4, this is a return from two years ago, and this is Vim. I finally feel like Vim is starting to catch up, the promise of the language servers and VS Code, and the way that it works. I guess I've said this every year. I know. I'm aware. STEPH: I'm laughing because I thought for a moment you're going to be like, I finally feel like it's working for me. [laughter] CHRIS: I finally learned how to quit Vim. I've just had one instance of Vim open for the last 13 years because I didn't know how to quit it. But that has been fine. And then I finally learned how to quit it. No. Vim is finally catching up. The Neovim just came out with a new version that's got tons of deep integrations VS Code-like features. Thanks to the wonderful work of the VS Code team and the respective language servers from all the different communities. The promise of the editor ecosystem rising tide lifts all ships is coming true, I think. And even right now, I haven't even jumped to that new Neovim version. But the version of Vim that I'm working on with the current config is great. It works. It does the thing. And that's awesome. And it's only going to get better from here I think. So 2022 is the year of Vim on the desktop. That is my strong bet. That's a joke about Linux in case anyone doesn't get it. It's not a good one. But it is a joke about Linux. So that's my number 4. Back to you, Steph, for your number 5. STEPH: [laughs] And this is another count for our laughs in parens for next year's frequency count. Well, I guess it is still this year. CHRIS: I absolutely love that that made it onto the list of top 10 things just [laughs] laughter off to the side. STEPH: All right. So for my final, number 5 is don't forget the fun. And I say this because while work can be very interesting and fulfilling, I have found for myself this year that I also really needed some downtime to just play, to just experiment. And initially, sometimes I was worried where I felt like a lot of the work I was doing often wasn't building, but it was more correcting or fixing systems. And I started to lose some of the joy that I had around coding. And I started to worry about am I losing the interest, the spark that I have for this career? And while I'm very fortunate to enjoy my career, I have become accustomed to the fact that I really like what I do. And so when I felt that starting to fade, it was a concern for me. But then I started picking up just some little fun things like one of them is Advent of Code which is created by Eric Wastl. And during the month of December, a new programming challenge is released each day, and there's a leaderboard and you can be as competitive as you like. You can use any programming language that you like because then you essentially solve the problems and then provide the answer. And then Advent of Code will let you know whether you have the correct or wrong answer for that exercise. And that sparked some joy, and it reminded me, oh, I really do enjoy this. I like a lot about this. But I have been so heavily invested in triaging that I was missing some of the fun that comes from just building something. And so that is my number 5 is don't forget the fun. CHRIS: I'm so glad you added that to the list because this podcast is depressingly serious at times. And I'm glad that we now have this on a list formally so that we can remember to not take things too seriously. But more seriously, [laughter] I do think that's a wonderful item. And we do have the possibility of really loving the work that we do. I find this work to be very fun. And there are different versions of it. And there are different companies and ways that it can go. But for me, this is something that I love to do that I find so much fun in but can get mired down in the details. And so being intentional and saying, "This should be fun. If it's not, what's going on?" That's at least something to look at. And where can I find the fun? And how can I revisit that? So I really enjoy that that is the final item that you're capping your list off with, in fact. So for me, the way that I've thought about this list as we've composed it over each of the years is what are the major themes? And for me, probably the biggest theme is that I have joined an early-stage startup, and I've joined on as CTO. So it's a very different role. It's a very different type of interaction. I'm not sure I've ever said the company's name before on this show because I'm a terrible salesman. The company is Sagewell Financial. And so we are trying to do something very ambitious. And the role that I'm in is a very interesting one. It's composed of pieces that have always been part of my work. There have been bits of mentoring, and hiring, and architecting, but then also doing the individual contributor work and all of those different pieces, and those will all be present but to varying degrees. And the amount of ownership I have over the thing is very different than the long history of consulting that I've done. And so I'm really excited to lean into that and to explore that and to find out what it feels like to code less because I think that's just kind of a given. It's already started to happen even this early on in the project, and I know it's probably only going to continue, which is an interesting one relative to your "Remember the fun." I find coding very fun. So that'll be an interesting one to see how it plays out. But I also find all of the other aspects of managing and guiding the technical portion of an organization really interesting. So I'm super excited to continue pushing on that, to go on that adventure. But yeah, it's very different. Or it's every single dial on all of those different measures is just turned up to 11 now is what it is. And I'm like, okay, cool, strap in. Let's go for a ride. This will be fun. STEPH: I really enjoyed those discussions about how your role has shifted and the different responsibilities that you're taking on as I have often felt that tension between managing and then coding. And I enjoy both, but then making time for both, and then which ones do you grow in? Because I'm still always growing and striving to be a better manager and a team lead. But then I also want to continue to grow and be a better individual contributor. And focusing in those two areas or trying to grow in both directions is hard. So then I often have to pick one to focus on. Maybe it's for a day, maybe it's for a week, maybe it's for a month. And I'm like, hey, for a month, I want to grow in this particular manager skill. But then that way, I feel like I have this more achievable goal. So all that is to say I really like your number 5. And I'm really looking forward to more conversations about how it's going and all the different things that you learned from being a CTO. CHRIS: Well, I think on that wonderful note, we should probably wrap up this episode and wrap up this wonderful year of The Bike Shed. As always, Steph, it's been such a pleasure getting to chat with you on these weekly tech talk and nonsense adventures that we go on. STEPH: Likewise. This has been so much fun. And when I mentioned earlier about having sparks of joy, Bike Shed is always one of those. I love these conversations that we have. It's been a wonderful year. CHRIS: Cool. Well, I will see you in 2022. 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 people 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.Sponsored By:Scout: Scout APM is leading-edge application performance monitoring 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 performance abnormalities -- like N+1 queries, slow database queries, memory bloat, and 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 worldwide call Scout their best friend and try our error monitoring and APM free for 14-days, no credit card needed! And as an added bonus for Bikeshed listeners: Scout will donate $5 to the open-source project of your choice when you deploy. Learn more at scoutapm.com/bikeshed.Support The Bike Shed
undefined
Dec 14, 2021 • 35min

319: Wins & Losses

Steph started a new project and shares details about the new tools she's using, including working on a remote dev environment. Chris shares a journey with Lograge and Rails flash messages as he strives to capture user-facing errors. They also discuss "silencing" flaky tests, using Graphviz to visualize data dependencies, and porting Devise views to use Inertia and Svelte. It's also interesting how different their paths have been this year! This episode is brought to you by ScoutAPM. Give Scout a try for free today and Scout will donate $5 to the open source project of your choice when you deploy. Joel Quenneville GitHub - roidrage/lograge: An attempt to tame Rails' default policy to log everything Graphviz Become a Sponsor of The Bike Shed! Transcript: CHRIS: Tech talk nonsense and songs, that's what people come to The Bike Shed for, variations on the Jurassic Park theme song, you know, normal stuff. 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. Let's see. So I've started a new project. So frankly, there's a ton of new stuff in my world. And I've been on the project for about a week and a half now. I started over the holiday, and it's been going really well. Still in that whole early stage with getting to know the application, the codebase, the processes, the team, all the dynamics. It's a large company. So I'm working with a small group of individuals, but there are about over 100 developers that work at this company. And they do have a lot of documentation, which has been very helpful. But there's a lot to learn in terms of setup and processes, specifically. So they have provided a laptop that I'm using to access their codebase. So I'm using their laptop. And then, I am also using a dev machine, a remote dev machine, that they have set up for me. So I need to be on their VPN and SSH into that dev machine. So that's novel as well. CHRIS: Ooh, I'm very intrigued by that bit, not that they gave you a laptop bit but the dev machine. This is in the cloud sort of thing? What is this? I'm very intrigued. STEPH: I don't know if I have concrete answers for you. But yes, for me to be able to access their codebase, I have to go into the dev machine. And then that's where then I can do my normal development work. CHRIS: So is this like an EC2 instance or something like that that you're SSH-ing into, and then you can run processes on it? Or is it closer to the GitHub dev containers thing that they just released? Or are you running with your local Vim? Is it a remote Vim? Are you using Vim? Is it VS Code? I have so many questions. STEPH: [laughs] I think it's more like the first version, although I don't know the backbone of it. I don't know specifically if it's an EC2 instance or exactly how it's being hosted and how I have access to it. But I did have to set everything up on it. So they started the dev machine up for me. Their DevOps team started an environment where then I could access, and then I did need to cultivate it to my own habits. So I had to install several things. I had to install Brew and Vim and also the tmux and all those configurations that I'd really like to have. They do have a really nice Confluence document that walks you through how to set up a connection between VS Code and the remote environment. So then that way, you can really just hang out in VS Code all day. And initially, I was like, okay, I could do this. And immediately, I was like, no, I love Vim. I'm going back to it even if I have to spend the 20, 30 minutes setting it up. I'm so comfortable with Vim and tmux that I stuck to my roots, and I didn't branch out into VS Code. But I think VS Code is one of the more popular tools that they're using. So that way, it feels more local versus having to work in a remote machine. I think I answered some of your questions. I don't think I answered all of them. CHRIS: Yes. I think you did answer all the questions. But just for clarification, the Vim and tmux and whatnot setup is that you're running SSH, and then on the remote machine, you are using Vim and tmux? Or is it a local Vim that is doing…I think Vim has some remote editing capabilities but not anywhere near what VS Code can do. STEPH: It's the first setup. So I am SSH-ed in. And then I have Vim and tmux running on that remote machine. CHRIS: Gotcha. Novel. STEPH: Yeah, it's a thing. It's working. So that's good. And it feels cozy. I feel like I'm at home. I feel like I can be productive. So that's great as well. Some of the other tools that I'm also new to, so they use Zeus, which is used to then speed up the booting of your application. And you can also use it for speeding up test runs. So very similar to Spring, which I think we've had some discussions about Spring and who loves it and who doesn't. [laughs] CHRIS: I don't know. I'm not...[chuckles] I feel like I remember Zeus. But Zeus is like three iterations ago of this preloader thing. I'm intrigued by that. I thought Spring had fully supplanted it in the Rails ecosystem but maybe not. STEPH: So this company has been around for a very long time. So there are a number of tools that I think they're using because that was the tool to use the day when they got started. And then it just hasn't been a need to move on to one of the newer tools to use Spring. So at least that's my current explanation for why we're using Zeus. And also, Zeus works most of the time. I'm frankly still getting comfortable with it. [laughs] I still have gripes about Spring too. CHRIS: 60% of the time, they work most of the time. STEPH: [laughs] So, Zeus is another new tool that I'm adding to my tool belt during this engagement. Another new tool that I'm using is Gerrit. And so they use Gerrit…it is used for managing their Git repositories. It is used for code reviews. And being as accustomed and familiar with GitHub as I am, that one has been a little tricky to then navigate and change the whole UI that I'm used to when it comes to pushing up code, reviewing code, asking for feedback on changes. And at one point, I was reviewing a change request for someone else. And there's a button on there where I was adding comments, but they were in draft mode. And I'm trying to figure out how to get them out of draft mode so that they're actually submitted, and the other person could see it. And I saw a submit button. I was like, cool. So I hit the submit button. And then it said something in red text about ready to be merged into main. [laughs] I was like, oh, no, I mean, maybe, but that's not what I meant to do. So I had to reach out to that person and be like, "Hey, I'm new to Gerrit. I don't know what I did. I hit a button. I hope everything's fine. Here's my review. Best of luck. [laughs] I think everything is fine. Nothing dramatic came out of it. But I had my own little dramatic moment. CHRIS: Wow, that is a bunch of new stuff. It's interesting. On the one hand, I totally understand projects get started, and there's a certain set of tools that are current at that point, and so then you're using them. And then, over time, it takes a very active effort to try and keep up with the new current, that new-new as we call it. But the trade-off there is really interesting because, at any given time, it never feels like the right investment to pursue the new thing to just upgrade for upgrading sake. But then the counterpoint is the cost to someone like you coming onto the project. And it's like, it's a bunch of new stuff. It's kind of old stuff. It's new for me, but it is old, and less documented, and less familiar. And it's also certainly less compatible with other things that are going on, almost certainly. And so, how to stay on top of those updates is always the thing that's really intriguing to me. I say as someone who started a project recently, and I have not thought about upgrading anything at this point. And we have bundler-audit I want to say is the one thing that we have in there. So if there's a CVE for a gem, then security-wise, we will be upgrading those. But otherwise, I haven't thought about upgrading our Ruby version or anything. And I think we're on 2.6 or something like that, which is a couple back at this point. And so it's something that's in the back of my mind. I feel like I should have a formal answer to this. Like, company-wide, how do we think about the process of upgrading? And Dependabot and things like that answers some of it, but that doesn't tell me when to upgrade Ruby, I don't think. It could. That would be annoying. I don't want that. But it's one of those many things that depends and is subtle. And you have to decide where you put the trade-offs and whatnot. So just an interesting thing. And to observe you now going into this project building and being like, there's a bunch of new stuff. STEPH: I think it really takes passion or pain. Those are the two things that then prompt us to upgrade. Either it's pain, and you need to change it to get rid of that, or it's passion. So you're really excited about the next version of Ruby or the next version of Rails. And I think that's fine. I think that's fine that those are often our drivers. But yeah, that is interesting. I hadn't really thought about that in terms of there's often no real strict process around when we upgrade except those are then the natural human catalyst. CHRIS: I think you're right that those are the catalysts. But I think quite often those cannot be sufficient to push us to do the work. And so what do you do in the absence of that? It's not really painful. And I'm not really passionate about it. But I probably should do it is the 80% of the time middle space that we live in. And so yeah, I don't have an answer to it. I'm more observing the question. But like so many other things, I feel like often we just exist in that awkward middle and got to find a way through, so how like life. STEPH: I was having a conversation with someone earlier a bit about these life cycles that we live in. Specifically, we were talking about consulting and how changing from project to project is so daunting. Because you go from I'm accustomed to this project, I'm accustomed to the team. And then all of a sudden you jump into this new project and with all these new things it can be really interesting. But then there's also this feeling of like, wait, I used to be smart, and I knew everything that was going on. And the team knew me, and I knew all the team processes, and I felt good. And now I'm in this totally new space, and I have to relearn, and I have to reprove myself and relearn all the company politics. And there's always that initial jumping from a sure space over to a very new space that always makes me then question and be like, yeah, I can do this, right? I can do this. And then I have to keep letting that voice build until about two weeks in. And I'm like, oh okay, I'm back in a good spot. I said two weeks; it's probably more like four. But there's still that grace period of a new project where you're leveling up on all the things and learning the new team. And as daunting as it is; apparently, it's what I like. Apparently, I like that roller coaster ride that comes from jumping from one project to the next. So on that note of a bit of novel insight into myself, what's new in your world? CHRIS: What is new in my world? Let's see. I think I've got two updates, two anecdotes to share. One, I lost the battle, one I won the battle. So we'll go with the lost battle first because that seems fun. So we have Lograge on this application, which Lograge, for anyone that's not familiar, is a library that helps with producing more structured and more complete log lines from a Rails application. You can tell it to do JSON log lines, which is useful for many of the tools that will receive your logs. And then with it, you can say grab me the controller name and the params but sanitized and this and that. And so, you aggregate a bunch more data than would traditionally be in the logs. In general, I've just found it to be a much better foundation. I find the logs to be more readable, and more informative, more useful, all those lovely things. But slowly, I've been looking at what's the other stuff that I want to have in here? What else would be nice to know? So one example is we use Inertia on this project. And Inertia has a particular way in which errors get mapped back to the front end. And it's an interesting little trick that involves the session, but that's sort of an aside. Basically, this is something that the user will see that I would love to know about. So how many users are hitting their head against the wall? Because typically, whenever these errors happen, that means this is a flash message or something like that we're going to show to the user. So we were able to add that into our log lines. Now we can see those. We can aggregate on them. We can do counts. We can do alerting and monitoring, all those kinds of fun things. So cool. That was great. That worked well. I then specifically…I mentioned the flash a second ago, but that's actually not…the Inertia messages will not show up in the flash. They end up in forms inline on certain inputs or whatnot. But we do also use the flash message pretty regularly as a way to communicate to the user success or failure or what have you. And I really wanted to get those into the logs. And I tried very hard, and I failed. I gave up. I threw in the towel. I raised the white flag. So the nature of the flash, which is something that knew in the back of my mind but I had never really experienced as pointedly as this, is the flash is a magic value within the Rails ecosystem that can be written to and then once read clears itself. That's the nature of how the flash is supposed to work. And it persists across requests. So it's doing some fun stuff there, which I assume is tunneling through the session or maybe putting it into a cookie. I'm not actually sure. But there's some way that you post to an endpoint, and then you get redirected to the show page. And on the show page, we actually display that flash value. But the flash is set on the controller endpoint that is handling the POST request. So this value spans across two request-response life cycles, which is interesting. And so the manner in which that works is Rails is managing that on our behalf. We write to it on the one side. And then, when we do the subsequent requests, if there's a value in the flash, we show it to the user, which is why occasionally you'll see those weird things where that flash message shouldn't show up. But it's like a sticky value that was left in the system that didn't get cleared via one thing or another. But I really wanted to put those into the logs. Like, what are we saying to the user is the thing I want to know. This is that question of like, what's my system doing at runtime? I understand what it's doing. I can read the code and understand what should happen. But what actually happened? Are users seeing this flash message way more than they should? That's a question I want to be able to answer. And I have lost the battle. I cannot find a way to read the flash value, put it into my loglines, but then also have it persist through. The first attempt I did, I was able to get it into my loglines, but then it didn't show to the user, which is a bad outcome. Because now I've read the value, Rails clears it, cool, that's fine. There is a flash.keep method. And that I thought would do the thing I wanted, which is like, oh, I want to read this value. I want to tap this value, I want to observe it, I want to peek at it. And I thought this keep method would do the thing that I wanted. It did not. It just caused the flash to be persistent. So now, anywhere I went had the same flash message for forever, which was not the behavior that I was looking for. I then tried, like, all right, just for exploration purposes, what if I reach inside and read the instance variables of the flash objects? Also did not work. Everything I tried did not work. And it had these fun failure modes that just made me very sad. Thankfully, we had feature specs that told me about this failure mode because I would not have known about it otherwise. This was not obvious to me on first implementation. But yeah, I lost, and I feel sad. And then I did the thing that we do, which is I searched Google, and there's nothing. I cannot find…This is one of those cases where like, I can't be the first person who wants to know what's in the flash. I can't be breaking new ground here. And yet I couldn't find anything on the internet. So that's where I'm at. STEPH: That's interesting. Yeah, I'm trying to think…I think I'm one of those people. I don't think I've ever tried to peek into the flash and see what's there ahead of time. And it makes me wonder if it's partially…so we can't peek into the flash. You've exhausted several examples or tries there. When you're setting the value of the flash, it makes me wonder if there's an order of operations that you have to pursue. So before you set the flash, you know what messages that you're going to share. So you send that off to the logs, but then also share that to the flash. So instead of writing the message directly to the flash and then having to check the flash, if you just stored that value elsewhere and shared it to the logs first. Is that a reasonable approach? CHRIS: It definitely could work. But that was in the space of this is getting weird enough. I thought about things like that, but I didn't want to do anything weird. And part of the benefit that I get from using Lograge is rather than having multiple lines for each request…so a request came in and rendered this partial and did this thing. It gets constructed such that there's a single logline, which is one big JSON object that contains all of the data about that request. And I really liked that structure because then everything's correlated like, oh, did we 404, or did we 302? And what was the message that we said to the user? And what were the params? It's all there in one line. I found that to be really useful. So I wanted to do that. I could just separately log it. But then I'm also worried of there is a statefulness there. Because again, the flash is written on one side and read on the…it's like a Hail Mary to ourselves between requests. Look at me with a sports reference. And so, I didn't want to try anything out of the ordinary. I really just wanted to find a way to just like; I just want to read this value but not like Heisenberg uncertainty principle observing changes in the system. I found myself in that space, and I was like, can't there be a way that I can just flash.peek? And I just want to take a quick look. I don't want to mess with anything. You do your normal thing, flash. Just let me know. And I do not have an answer for it yet. And for now, this is one of those nice to have, not an absolute requirement. So I wasn't yet in the position of okay, fine, let's do some out-of-the-box ideas here. So I'm still in the in the box phase, I would say, but who knows? Maybe down the road, I'll be like; I would really love to know what the flash message was for that request because this user is seeing stuff that we do not understand. And that information would tell us the answer. So we're not there yet. But I was surprised by how thoroughly I was defeated by Rails and the flash message on this adventure. STEPH: I am equally surprised. I wouldn't have thought that particular achievement would have or is proving to be that hard or, frankly, not doable. So yeah, I'm intrigued to see if anybody has thoughts on it or if you do find a different solution because Lograge is one that I haven't used. But I would be surprised if other people haven't had a similar request of like; I want to be able to store what's in the flash message. Because like you said, that seems super helpful. CHRIS: Well, certainly, if I do figure anything out, then I will share that with the world. But yes, part of this is putting it out there into the universe. And if the universe happens to send me back an answer, I will happily accept that. But yeah, again, I had two stories, and that was the one where I lost. I'm going to send it back over to you because I'm interested in anything else that's up in your world. And later, I'll tell the story of a victory. 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. STEPH: I have a victory that I can share as well, and I'm excited to hear about yours. So to share a bit more context about the project that I'm on, we are focused very heavily on improving their test suite, not only the time that it takes to run the test suite but predominantly addressing a lot of the flaky tests that they have. Because that is a huge pain point for the team and often leads to the team having to rerun tests. And so, there are a couple of areas that we're very excited to make some contributions. The first part is that we are just looking at those flaky tests to figure out what is going on and how can we address these? And one of the nice things, one of the tools that they're using TeamCity is the tooling that they're using to run their automated test suite. And TeamCity will let you mute tests, so then that way, if you do encounter a flaky test, you can mute it. So then, at least it's not impacting other people. I say this with some asterisks that go along with it because, for people who can't see, Chris is making a very interesting face. I think you have thoughts on this. And the other thing that they will show is a flip rate for the flaky tests, which is really nice, too, because then you can see which tests are flaky the most. So then that helps us prioritize which ones we want to look into. All right, I'm going to pause so you can respond to that comment I made about muting tests. CHRIS: I'm intrigued. I talked in a recent episode about adding RSpec::Retry. So the idea of flakiness being a thing that exists and trying to decide how much engineering effort to apply to fixing it. But the idea of muting it and especially muting it in the UI, not in the test suite or not having that be something that's committed, there's something about that that caught my attention, and thus apparently, my eyebrows raised. You saw that. [laughs] But I don't actually know how I feel about it. This is such a complicated, murky area that I wish I had a stronger set of beliefs around. It was interesting when we talked about the RSpec::Retry thing. I think you rightly pushed back on me, and you were like, that's interesting, maybe don't do that. And I was like, that's a fair point. [laughs] And so now hearing you're in the quagmire of flaky tests, and yeah, it's an interesting space. STEPH: Well, I think my hard belief is that muting tests is a thing that we shouldn't do. It's going to lead to more problems, and you're not really addressing the issue that you have. It is a temporary solution to a much bigger problem that you have. And so it is a tool that you can use to then buy you some more time. And so that is the space that this team is in where they have used this particular tool to buy them more time and to be able to keep shipping changes while realizing that they do still need to address these underlying issues. So it is a tricky space to be in where essentially, you've gotten to the point that you do have these muted tests. It is a way to help you keep going forward, but you are going to have to come back to it at some point. And so that's the space that I'm in right now joining the team is that we have been brought in to help some of their engineers specifically address this issue while ideally letting the rest of the team continue to focus on shipping changes while we address the test. Although I really think there's going to be two angles that we've talked about in how we're going to help this particular codebase. One of them is that we are going to address a flaky test. But the other one is empowering people that they feel like they have the time and the knowledge that they can address a flaky test and also not contribute more flaky tests to the codebase. But I appreciate that you called me on that a bit because we've had those conversations around when we should actually address something versus muted, all the interesting trade-offs that come along with that conversation. So this particular flaky test that we addressed earlier this week is specific to hard coding primary IDs. The short version is that it's bad, don't do it. The longer version is that they were having a test that was failing intermittently because it would pass the first two runs, but then it would start to fail for all future runs. And the reason it would pass for the first two runs is because when they were setting the ID for a record that the test setup is creating, they were looking for existing records and saying, "Hey, what's your latest ID?" And then I'm going to guess the next ID. I'm going to add one to that to figure out what the next ID should be. Some additional context, when the tests boot up, there's some data that's being created before the test run. So then that's why they're checking to see, okay, what records already exist? And then let's add one to that. The reason that fails sometimes is because then once the tests have run, the Postgres IDs aren't being reset, so they're using a truncate approach. So then, when the test runs once or twice, that works. But then, at some point, there's a collision between those IDs where they tried to guess the next ID, but then Postgres is also on that same ID, and it ends up failing. There are also some callbacks. There's some trickery afoot. It took a little while [chuckles] to work through these tests to understand why they're failing. But the short version is that we thought we had to restructure the data in a way that no longer required us to guess what the next primary key should be for a record. We could actually use Factory Bot to generate that record, and then ask Postgres, okay, what ID did you assign? And we're going to pass that in. And that part was really challenging when you're in a new codebase, and you are learning the domain knowledge and exactly how data should be structured. So that was one challenge of it. The other part was that a lot of the data relies on each other. So then figuring out the right hierarchy in which we could create the data. So we didn't have a circular reference at some point. It took some time. And Joël Quenneville, who's on the project with me, used a tool that I found very helpful. It's called Dataviz. He went through and documented the let statements, the data that's being created, and then it generated a nice tree structure that shows you okay; these are your dependencies. This is the test setup that you're using. And then from there, just by changing a few lines in that particular file that used to generate that Dataviz tree, he would move it around. And we could simulate what we were already mentally trying to construct in our head. So as programmers, we're already thinking, okay, I know this record needs that data. And that data needs that data before I can build this. But this actually turned it into a concrete visualization where we could see it. And I was really struggling. And he was like, "Hey, I got it into a visual form that we can look at. And there's a circular reference. That's why this keeps happening and why we're not making progress." So then, using that, we were able to then reformat some of the dependencies, look at the graph, see that we didn't have that circular reference anymore. And then we could implement that in code. And it really helped me to be able to walk through that visual aspect because then I could say, okay, this is all the stuff that I'm trying to mentally hold on to, but instead, I can just look at this and know it's going to work. I don't have a circular reference. It also helped concretely show why the previous efforts were failing and why we kept running into some issues. So I'm really interested now in Dataviz because I found it very helpful in this particular case. And I'm very intrigued to see if I can apply this to more tests that I'm trying to fix and to see if I can start out with here's the current structure. Here's where I'm trying to go. And then essentially build that graph first before I start changing the code around. I would love to have that optimization. And I feel like it would speed up the process. CHRIS: It was funny as you started to say that I had observed some tweets going out into the world recently. And I was like, this is Joël. This is definitely Joël talking about these things. As an aside, for anyone who doesn't follow Joël Quenneville on Twitter, @joelquen, I would highly recommend it. We can include a link to Joël's Twitter in the show notes. Joël is one of the clearest thinkers and communicators about programming that I have ever worked with. And in particular, what you're describing of the data visualization is something that I think he does incredibly well. Often he'll make blog posts, but they'll include just simple little visualizations, little images, or diagrams, or flowcharts that just so concretely encapsulate an idea and express it so much better than text ever could. And so, in so many ways, I look to Joël's writing, both on Twitter, in the blog, in many places. And I just appreciate so much what he puts out there and the manner in which he does it. So I was by no means surprised when you said, "Oh, and I'm working with Joël on this project." I was like, yes, I bet you are. That sounds true, and in particular, some of the conversations about flaky tests and determinism and all of that. So yeah, the visualization stuff is also particularly interesting in taking a system that it's very hard to hold all of this in our heads. But that visualization, the tree and/or graph thing at play, having that in a picture and being like, oh, look, there's a cycle now. There we go. Can't have those. That's not okay. That's a really interesting solution that's just very cool to hear about and presumably led to a good outcome where you were able to break that cycle. And now you're happy and deterministic in your tests. STEPH: Yeah, it's one of those approaches where I wonder if it was helpful afterwards and how can I make it helpful beforehand? Because it felt like a confirmation of the pain in the process that we had been through. And I'm eager to see if now I can apply it ahead of time and save myself some of that pain. That's where I get really excited. But yes, it was a successful outcome. And we have fixed that particular flaky test. But I'm very excited to hear about your victory from the week. CHRIS: It's a shared victory. It was a team victory, just to be clear. But we are working in a system that is using Inertia. Inertia.js is a project that I've talked about a number of times on the show. I'm a huge fan of it. It is the core architecture of how we're building our application. But as a very brief revisiting of what it is, on the server-side, we have Rails, and Rails is acting in a pretty traditional way. We do not have an API. And on the front end, we have Svelte, which is a JavaScript view layer framework. Inertia sits between them and binds the traditional Rails MVC architecture and the Svelte front end. So again, there's no API in the traditional sense of this is a REST endpoint, and we hit it, and we get some data, and then the front end holds on to that in a store. None of that is going on. Inertia does a wonderful job of marrying these two concepts and allowing us to use familiar programming techniques on the server-side but then also have a more future-friendly front end. Animations and transitions and things like that are now totally possible while not throwing away the entirety of our programming model that we've had in Rails server-side applications. That's all well and good. Almost all of the UI in our application is rendered via Inertia and Svelte. That's great. We love it. The one caveat is Devise. So we have Devise on this project, and Devise comes with a lot of views built-in. And we have both an admin and a user model. So we have sign in and sign up, and confirm registration, and forgot password and all of these different views and flows and things that Devise just gives you out of the box. And being an early-stage startup, it was not a good time to revisit any of that or to try and build it from scratch or any of that. We just wanted to build on the good known trusted foundation that Devise gives us. But the trade-off there is that now all of our Devise logic lives in this uncanny valley. It's the only stuff that is in ERB views. Our styling, thankfully, we're using Tailwind, and so we are able to have some consistency between the styling. But recently, we redesigned the flash messages on the client-side in our Svelte pages. But on the server-side, they are a little on the Devise-side because Devise is the only pages that are being rendered truly server-side. They look a little different. And this is a pain that we felt, that inconsistency or that mismatch between the Devise views. And then the rest of the application is a pain that we felt but one that we consistently were like, I don't think it's worth the effort to try and change this. Finally, this week, we've been doing a lot of work on our user onboarding funnel. So the initial signup flow going through it's a progressive form screen where you go in between different pages. And a majority of it is implemented in the Inertia and Svelte side of things. And it's very nice and very fun to work with. But the signup form, the user signup form, is in Devise, and it's a traditional Rails server-rendered post, and then all the normal stuff happens. We finally decided to bite the bullet this week and see how painful it would be to port that over to Inertia and Svelte. And spoiler, it was awesome. It was very straightforward, and coming out of it, immediately, the page was largely the same. The server-side code was largely the same. But now we had things like when you submit this form, if there's a validation error, we don't clear out your passwords because we're staying on that page on the client-side. We're taking advantage of the way Inertia's error flow works. That's a subtlety of how Inertia works. That's probably more detail than we want to get into here, but it's an awesome thing that works and is great. And so immediately, this page just got better. We got inline errors for each of the fields. We were able to very easily add a library called Mailcheck, which I've talked about on an episode a while back. But this is a thing where if you have a typo in your email address, we can say, "Hey, you have a typo in your email address. And if you click this link where we suggest the alternative, we'll just replace it inline." That would have been really awkward to wire up in our Devise view. It would have been some jQuery-esque script tag at the bottom of the view page that doesn't stop…We don't have jQuery actually at this point. We wouldn't have jQuery. And we could certainly, but it would only be for that view. And it would be weird and different in a fundamentally different programming model. It was trivial to do in the Inertia and Svelte world once we had made that port over. This was always my hope. This was the dream that I had in mind. And it speaks to the architecture of Inertia. And Inertia is a really great abstraction that is very minimally leaky. I won't say it has zero leaks because no abstraction does. But this was my hope is I think the server-side should mostly stay the same. And I think the client-side, we just take an ERB template, turn it into a Svelte template, and we're good to go. And that has largely been the case. But suddenly, this page is so much more. There are subtle animations as things come in. And there are just lots of nice features that were trivial to add now and that fit with the rest of the programming model that we have throughout it. So that was awesome. STEPH: That is awesome. I love these styles of updates where there's like, oh, I had a loss this week. But I also had this really great win because that feels just so representative of a typical week. So I love this back and forth. CHRIS: It's also that sequence is how the week went. So the loss happened earlier in the week, and then the win happened later in the week, which is how I would prefer it because now I'm going into the weekend with a win. Like, cool, I'll take it. Had it gone in the other direction, I would have been like, oh man, Rails beat me. But I guess it's the weekend now. I'll forget about it for a little while. STEPH: Yeah, that definitely helps to end on a positive note. CHRIS: But yeah, I don't think too much more to say about that beyond it was both really nice to get the added functionality to get the better, more user-friendly behavior in this view that naturally falls out of this programming model. But also to have that reinforcement of my belief in Inertia as a good architecture. Not only did we get some really nice stuff out of doing this port, but it was also pretty straightforward because Inertia sits so comfortably between the pieces. And that's a story that I really like. I want more of that in my programming world, where to change this thing requires changing everything in our app. Oh no, this is sad. No, this was a great example of we were able to very minimally change things and get a much better experience out of it. So once again, I am very pro Inertia.js STEPH: It's interesting to me how different our paths have been this year where I have been working on applications that are brought on thoughtbot to then help out with some of the concerns that they have, either their application is going down, or they have a test suite that they need to improve, or there's a lot of triage that's involved. And so it makes me very excited to hear that, when you are building stuff, and it's going really well and how awesome that is. Because then I feel like most of my world has definitely been more in the triage space, which is a very interesting and fun space to be. But it brings me a lot of joy to hear about wins from let's build new stuff and hearing it be built from the ground up and how well that's going. CHRIS: Well, I'm definitely happy to provide that. But also, I want to be realistic and be like, I’m just writing next year's legacy code right now, let's be honest. I'm very happy with where we're at in this moment. But I also know how early I am in the project that I'm working on. And I'm burdened with the knowledge that I'm certain one decision that I'm making of the many that are being made I will deeply regret a year from now. I just know that that's true, and I can't let it slow me down. I got to just keep making decisions and do stuff. But I know that there's going to be one. I know that a year from now, I'm going to be like, why did we choose that option? But it's sort of the game. STEPH: [singing] We'll just know that there's something strange and your code won't change. Who are you gonna call? thoughtboters! CHRIS: Well, yes. I will definitely be calling you when I find myself in the uncertain times of legacy code of my own creation. So I look forward to that, frankly. But that's a problem for a year; I don't know, maybe two years from now. Who knows? But for now, what do you think? Let's wrap up. STEPH: Let's wrap up. The show notes for this episode can be found at bikeshed.fm. CHRIS: This show is produced and edited by Mandy Moore. STEPH: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or a review in iTunes as it really helps other people find the show. CHRIS: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed on Twitter, and I'm @christoomey. STEPH: And I'm @SViccari. CHRIS: Or you can email us at hosts@bikeshed.fm STEPH: 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.Sponsored By:Scout: Scout APM is leading-edge application performance monitoring 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 performance abnormalities -- like N+1 queries, slow database queries, memory bloat, and 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 worldwide call Scout their best friend and try our error monitoring and APM free for 14-days, no credit card needed! And as an added bonus for Bikeshed listeners: Scout will donate $5 to the open-source project of your choice when you deploy. Learn more at scoutapm.com/bikeshed.Support The Bike Shed

The AI-powered Podcast Player

Save insights by tapping your headphones, chat with episodes, discover the best highlights - and more!
App store bannerPlay store banner
Get the app