The Bike Shed

thoughtbot
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
undefined
Dec 7, 2021 • 44min

318: Successful Skills with Edward Loveall

Fellow thoughtboter Edward Loveall joins Steph to cohost and talk about alternative frontends and his own that he created: scribe.rip: an alternative frontend to Medium, learning about what it's like to be a manager/non-IC, and helps answer a listener question re: how do you think about empathy in your 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. Empathy Online: Edward Loveall Scribe GitHub - mendel5/alternative-front-ends: Overview of alternative open source front-ends for popular internet platforms (e.g. YouTube, Twitter, etc.) 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. And this week, Chris is taking a quick break. But while he's away, we have a guest on today's show. Today's guest is fellow thoughtboter, and wonderful friend, and British accent enthusiast Edward Loveall. EDWARD: Oh, hello, Steph. It is lovely to meet...No; this is not my real accent. Anyway, hi, friends. [chuckles] STEPH: [laughs] Hello, British Edward. I am so excited to be chatting with you today. Are you going to maintain that accent throughout the whole episode? EDWARD: No. There's no way I could do that. I need a lot more professional actor training to be able to maintain quality of that level, I think. STEPH: That's fair. I won't hold you to that standard. I was reflecting on preparation for this chat. I've been thinking about all the fun that we've had together, the time that we have worked together at thoughtbot, all the remote coffee walks that we have gone on together as we've talked through consulting challenges or coding challenges. And I realized that we have never worked on a project together, which is wild to me. EDWARD: Huh. Yeah, I think you're right. That is wild. Because I've been here three and a half years, and you've been here even longer than me. So in three and a half years of overlap, we've never done that. STEPH: And yet we've still always found ways to hang out. EDWARD: We make it a priority, you know. STEPH: I think we need to...we might have to bribe somebody for us to get on a project together. EDWARD: I'm pretty sure we know the person to bribe. STEPH: We do. EDWARD: We can go talk to our boss and make that happen. One thing we've both done in our career here at thoughtbot, too, is we have gone from individual contributor to being a manager, which is a cool transition. STEPH: That's a really good point. That is fun that we have embarked on that journey together. I was very much encouraged to become a team lead, and that was very helpful. Because I'm the type of person where I'm not sure I would have put myself up for that role. I'm very thankful that others encouraged me to do so because I really love it. There are certainly challenges with being a team lead. But overall, I have very much enjoyed the role. Just to provide some context for being a team lead a thoughtbot, because I feel like those management roles tend to differ from company to company as to the level of responsibilities that you have. So for us in particular, it's really focused on leading a team of developers, usually two to three developers, and conducting regular one-on-ones to ensure that they are fulfilled and are successful in their projects and their growth at thoughtbot. And then helping them become senior developers if they're not already and essentially coaching them through difficult development and consulting scenarios. EDWARD: Yeah, there is still an expectation that you are an individual contributor in some form on client projects. It is not just a management position. STEPH: Yeah, that's a good point. For me, that context switching is often what makes it challenging but yet also helps me still feel that I can coach somebody and that I can have one-on-ones because I am still in the trenches. I'm still contributing to client projects. And so, it really helps me still stay in touch with the work that's being done and the struggles that people will face. Let me say again I am positive I wouldn't have pursued this path if I lost my IC status. I really like that part of the role. That's really a split. How about you? EDWARD: Yeah, and I still do. We've been experimenting. So thoughtbot generally does four days a week on many projects. So we do four days a week with our client, and then we do one day a week as investment. And team leads, at least on the team that we are on, have been experimenting with just doing three days a week on a client, one day dedicated towards team lead, and then one day for investment. I like that split so far. We're still seeing how it goes, still pretty early on in that experiment. But I've enjoyed continuing to be in the trenches, as it were, and working sometimes with the people that report to me so that we can really grow in the same way. There's a lot of context shared there. And that's been really wonderful. STEPH: Yeah, I have some specific questions I'd love to ask you about that shift in schedule. Because in some of our meetings, there has been discussion about that ability to context switch between I'm only billing three days now instead of my typical four. And I now have more time to focus on team lead priorities, but then that also means I lose a day with client work. And so there's that battle going back and forth between focusing on client work and also focusing on team lead work. So I'm going to leave that as just a teaser because I want to come back to that. But I'd really love to circle back to earlier in the year when you were thinking about becoming a team lead and correct me if I'm wrong, but I think you were pretty hesitant about it. And you were still deciding if it was something you wanted to do. Do you recall what helped you make up your mind as to which path you wanted to take and why you chose this one? EDWARD: Yeah, that's a great question. I did also get some encouragement, a pretty light encouragement from a previous co-worker. And that was helpful, but I turned it down initially. Someone asked, "Hey, are you interested in this?" And I said, "Nope, definitely not." And, I don't know, a year-ish later, I then ended up applying. And I think what happened in the intervening year was that I started to naturally do some of the work of a team lead primarily, checking in with people and talking with them, pairing with them on things more regularly. So I felt as if I was already doing some of the work, not exactly running a one-on-one, not getting people promoted necessarily. But I cared about the people I was working with and wanted to see them grow and be happy and thrive. That realization helped me think, oh yeah, I'm just kind of doing this. And I should maybe apply for this role. STEPH: Wow, that resonates so much. I've heard that from other folks, too, as they have progressed into team lead or other management roles is it was often they already felt like they had started doing some of the work, or there was some natural inclination to start taking over those activities. And so then it felt right to then actually acquire that title and take on those responsibilities officially. Well, how's it been going? You had almost a year now. So you had some of those hesitations at the beginning. How's it been? What do you think of being a team lead? EDWARD: Yeah, I'm really enjoying it. It is a challenge like you said. But that's every job, right? Every job should be a bit of a stretch. So I did come into it with some natural inclinations of wanting to talk to people and check in with them. But there are all these other pieces that I wasn't good at. One thing that has been really challenging is instead of completing things myself, being that individual contributor, is trying to coach and sponsor people to do something that I would do. And I think the hardest part about that is they may not be as far along in their career as you are. And so it is hard to watch someone struggle in the way that you used to struggle without saying, "Oh, here, let me just do that for you.” And I think what I started to realize is that the efforts that I'm putting in I can really be a force multiplier and end up effecting more change than what I could do by myself. Like, if you think about it, I have four reports right now, and they're all really smart and talented people. But let's just say they were half as good as I was. That is definitely not true but just go with the numbers here for a second. If I could teach them to do what I do, even if they were half as fast as me, because there are four of them, they can get two times the work done. The math adds up in a way where if I can unblock those people, help them just get to the next one little step, do whatever it is that they need, they're going to do way more than I could by myself. And really wrapping your head around that and the advantages there is so hard but so rewarding once you figure it out and get it going. STEPH: Do you feel like anybody told you that up front going into taking on some more management responsibilities? Or is that something you learned as you went? EDWARD: I definitely learned that as I went. I got some great advice from Josh Clayton, who we work with, and he's been a manager for a long time. And that's a lot of how he thinks about it. And he encouraged me to do things like pairing with everybody on the team or running little workshops to teach, to fill in knowledge gaps for people asking questions, instead of giving answers, to help them find their own answer. And that's all been really, really helpful. STEPH: Yeah, that's one of the things that I have valued very much about our culture. I've seen some other companies struggle with is that when someone does get elevated into a management role that they still need support. They still need to be coached. And they also need room to make mistakes and grow. And at thoughtbot, I feel that we have been very supported and where there's someone that I can still get mentoring and coaching from. And I can learn to be a manager on the job versus I'm not just put in a position where I'm going to fail or just put there without the expectation that I still need to grow as a manager and as a person as well. So that has helped me out tremendously as well. You highlighted the idea of pairing more with others and then asking more questions around providing answers. And as you're learning those skills or as you've acquired those skills for being a team lead at thoughtbot, have you found those skills also transition well to client work? EDWARD: Yeah, they do. There's a lot of overlap, especially around gaining trust with somebody. I'm gaining trust in one-on-ones, but I'm also gaining trust with my client or helping my client understand something. This gets a little more into the client-side of it. But a lot of times in client work, I'm looking to bridge a gap. I understand something because of my consulting experience, and they want my knowledge and consulting experience. But it's hard to just go in and say, "Do X or do Y." And in the same way, with somebody who's reporting to me or who we're having a one-on-one, it's not usually very helpful to just say, "Do this, do that." You want to help them understand the why and bridge that knowledge gap to get to where you want them to be and where you think they should be. Those really do go hand in hand, and I have used a lot of the same skills. Giving feedback also has been a huge thing to share. It's really, really hard to give critical feedback to somebody. It's very easy for them to shut down and not take the feedback, which is the opposite of what you're trying to do. And the same can be with clients. Like, they've gotten to where they've gotten to because of whatever they've done in the past, and trying to show them why what some of the things they're doing is maybe not ideal is really tricky without triggering that flight or fight response. So yeah, there are lots and lots of crossover to answer your question. [chuckles] STEPH: I get so excited when clients that have brought on thoughtboters recognize that we are there temporarily, that we bring an outsider perspective. And they will set up essentially reoccurring; maybe it's weekly, maybe it's monthly to say, "Hey, give us feedback. Let us know what are you seeing? What do you think about the team? What do you think about our processes? What would you like to change?" And I don't mean just in a retro setting that you're having with the team, but it may be meeting with leadership of that company to give them that feedback directly. And that's awesome. It's rare because, I mean, that takes confidence on their part to be able to say, "Hey, give us all of your feedback, constructive, positive, whatever it may be." But I feel like they get so much value out of doing that where they really get to leverage the fact that they have brought in these external members. And they get to hear from them as to how things are going and insights that they may be missing or not hearing from their people otherwise. EDWARD: Agreed. STEPH: Circling back to the manager IC path for a moment, I have a question for you because I often find myself asking this question to me or sometimes other people asking this question. But how do I know which path to follow? How should I explore do I want to be a manager? Do I want to continue and invest in my individual contributor skills and really lean into that path? Have you found any resources that have really helped you or ways that you coach others through that scenario? EDWARD: I probably don't have a very interesting answer just because I'm going to mostly repeat what I think I said. But I think it's still so relevant and valid, which is, do you find yourself doing some of the work that a manager does? And it doesn't necessarily have to be the thing that I did, which was reaching out to people and checking up on them and seeing how they're doing. It could be that you really, really like running big team meetings or something like that. You just get a kick out of doing that kind of work. Or maybe you really enjoy working less on yourself and more on the group around you. That could also point to more of a technical leader. It doesn't have to be a person leader. So I think I would look for where you find yourself wanting to effect change and figuring out if that fits into a manager role or not. And I've had people tell me they definitely do not want to be a manager, and they know that for sure and people that are on the fence. And I think that's another useful thing is to ask your manager what they do as the job and see if that's interesting. See if any of those things spark joy for you, as it were. STEPH: I love the approach of just flat out asking your manager or someone that you see where perhaps you would like their role and saying, "Hey, what's your day like? What do you do? And can I be part of more of your day just to see if I would be interested in this type of work? Essentially, can I shadow some of the meetings that you're in?" I really like that idea. And I think in the past, I would have been more hesitant about this approach. And it certainly depends on your company's culture. But there's a part of me that's like, just try it out. Like, if someone is encouraging you to go for a management role or to go for maybe it's a stronger individual contributor role, maybe it's being a principal engineer or something else, but if there's someone that's already there encouraging you or if it's just yourself and you are your own cheerleader, then go for it. Try it out. See if you like it. Take some notes. See if what you thought the job was going to be like actually matches reality. Because then, at the end of the day, you can always decide to change your path. And if you are at a company that supports that type of experimentation, then you can step back to your current role if you decide that you don't like it. Or you might find that there's a really nice mix in there. But I feel like, with time, I'm getting a bit more bold with strategies in terms of just trying things out, even when it comes for technical challenges as well. Like if there's something that you're really nervous about or there's some big technical problem or something that the team is working on, and you're really skittish and nervous about it, just go ahead and say, "I'll do it, or I'd love to work with somebody on it," and then try it out and take some notes, see how it goes. EDWARD: You could be really sneaky too. You can say to a colleague, "Hey. You want to get lunch?" And like you turn that into a secret one-on-one. Or you offer to run the retro board during retro, or you step up for doing a bunch of pull requests that week or something like that. You can try these little test things without even having to let somebody know or committing to anything publicly or even privately. Just really internally to yourself, you can try to take some of those steps. STEPH: I like the sneaky success ladder. People won't talk about that one as much. [laughs] That's how I definitely found out that I didn't want to do sales. There was someone that I was talking to that was interested in working with thoughtbot, and Josh Clayton was very supportive of like, "Do you want to come along and be part of the conversation?" I was like, "Yeah, sure." And so I went along, and it was fun. But I definitely walked away like, yep, I don't want to be part of sales. I really like everything else minus this part. [laughs] EDWARD: Yeah, it's good to know. It's good to know. STEPH: Circling back just a bit to something you said earlier, you had mentioned that as you were becoming a team lead, you realized that helping others be successful at their job was really then what led to you feeling successful as well and that you could be a force multiplier. And you'd mentioned that a lot of that work comes down to bridging knowledge gaps. And I'm really curious because this is something that we're always working on at thoughtbot. We are looking to identify what skills people would really like to learn. How can we help people learn those skills? And I'd love to know more. How do you go about this? How are you helping people bridge those knowledge gaps? EDWARD: Yeah, so that is a doozy of a question. I have a couple of different answers. First is something I talked about before, building trust. And there's a bunch of different ways to do that. And I see trust as the foundation of almost everything in consulting. If you don't have that trust, it's really hard to deliver feedback like we talked about. It's hard to bridge that knowledge gap. Because effectively, nobody knows who you are, and what you're doing, what's going on, why you are coming to talk to them. It's really strange. And we can come back to how to build trust. But once you've built that trust, I approach bridging that knowledge gap in a couple of different ways. One is asking questions instead of giving answers. The goal behind this is I want them to think about their goals. And that will often help lead them to some answer to bridge that gap that we have. I have some idea. They have another idea. If I can ask the right open-ended question, they will walk themselves across and get to where I want. Now, that doesn't always work. Another strategy I've found is outlining a bunch of different possible solutions and their pros and cons. That has done two things. One, it helps them understand where I'm coming from, what my goals are in relation to what they're trying to do. And another one is that actually tends to gain a lot of trust. In the meantime, you're showing your expertise. You're showing that you're really considering all their problems. Because almost every solution has trade-offs, there's very rarely a silver bullet. And so it's really helpful to say, "Well, here's the pros, here's the cons. Here's where I think you should go, but you know your business better than I do. And I've outlined all the things here. So whichever way you want to go forward on this, let's do that. And let me help you get there." Joël and I, a colleague that we both cherish dearly, we did that on a project recently, and it was really, really successful. We put a lot of work in and helped them get to a really difficult architecture decision. And it could have gone one of, I think, four different ways. And we were sort of vying for one. They were vying for another. And we found a couple more in the middle, and I believe we went more towards the middle. And we were both pretty happy with how that turned out. STEPH: I really, really like how that approach gives someone so much autonomy, and they're part of that decision. So you're not just saying, "Hey, you need to do this," and then just following through with it. But instead, it's saying, "I think I've heard everything. I think I understand the different problems that we're facing. Here are my suggestions, but you still have more context. What do you think, or which option would you like to pursue? I really like that option." EDWARD: Yeah, because you're always writing this line as a consultant of like, they did bring you in for your skills and expertise and theory. But you really want to level them up so that they can make the right choices because that ultimately is...like, their success is your success as a consultant. That's the job in a lot of ways. And so yeah, giving them the tools they need to make the right decision is so often the job. And I think that can get lost in the shuffle of, oh no, we have to meet these sprint goals. Or I got to get this ticket done or this bug fixed or something. And stepping back to get them to a better place is another goal that you can get to down the line. It's not to say shipping tickets is bad [laughs] or getting the sprint goals is bad. It's just another facet. Have you had any aha moments in consulting? STEPH: Oh my gosh, I have had so many aha moments. I think most of them, for good or for worse, are here on The Bike Shed, or at least they've been shared here on The Bike Shed. [laughs] EDWARD: Yeah, you should write a book of them all. STEPH: Could we just grab the...I'm lazy. Can we grab the transcripts? We'll just turn that into a book. EDWARD: [laughs] Yeah, just put it all together, call it The Bike Shed Diaries. STEPH: Yeah. Oh, I like it. Okay, all right, that'll be next week's task. We'll publish The Bike Shed Diaries. [laughter] Specifically, in terms of bridging aha moments for helping someone bridge knowledge gaps or even for myself is I will often focus on what skills do you need today to make your job easier? What challenges are you facing? And also, what skills would you like to have six months from now? So that way, you are meeting the needs and the requirements that you really need today to fulfill your job. But then also six months out, we're still looking towards the future. Maybe that's also more job requirements related, or maybe it's just for personal growth, or the areas that you're really excited about. You really want to contribute to an Elixir, open-source project, or something more specific that contributes to your fulfillment. So when it comes to knowledge gaps, those are often the questions that I'm asking are, what do you need this week to make your job easier and to make your life easier? And then where would you like to be in terms of what skills would you like to have six months from now or what concepts? It may even be too lofty to say what skills because that could be huge to say that I want a whole new skill to be able to work in a language. So maybe it's something that's more specific of like, I'd really like to understand forms a bit better six months from now, or I'd really like to feel a little more confident with SQL, or maybe you'd like to take a look at Arel, things like that. And then set those targets and then check in to say, "How's it going? How do you plan to learn these skills? Would you like help learning these skills? What are some resources?" Because I am not always the person that can help someone acquire that knowledge. So in that role, I'm often a facilitator where I will say, "Cool, you want this. You're interested in this particular skill. I don't know that skill. But I do know someone else who's really good at this. So let's get you all connected, and then you can work together on this." EDWARD: And to dovetail a little bit with that manager individual contributor piece we were talking about before, that's another piece we didn't really talk about, which sounds like sponsoring. It's not just you doing the thing for your report or even coaching them necessarily. It's how can I get my report into a situation where they can exercise that skill or connect them with somebody who can help them with that thing? I'm still working on that one, honestly. That's a really, really difficult one. That's not something that comes naturally. STEPH: When you say that's the part that's still challenging for you, is it the connecting of one person to someone else to learn a skill? I'm curious to hear more about which part of that is challenging for you. EDWARD: I think I don't always think of sponsorship as a tool that I can lean on. It just doesn't come to mind as naturally. I think the very natural thing to do is mentor first, which is like, here's what you should do. It's kind of giving somebody a fish. Coaching then is more like teaching them how to fish. And then I don't know if we're going to extend this analogy farther. Sponsoring is like you're going to open up your own fishing teaching school or something. [laughs] And that just doesn't always occur to me. I don't necessarily think like, oh yeah, like my friend over here could totally teach you about this technical skill that you're trying to learn or set you up to speak at a conference or something like that. It's a much different level of being a manager that I'm just not used to yet. I'm getting better at it. But it doesn't come naturally. STEPH: Yeah, that's a very powerful form of managing someone as well because then you are helping that person go beyond their current bubble of who is their manager in their team and then helping them shine in other circles. And that's incredible and also something that I am always working on getting better at. EDWARD: Let's get better at it together. STEPH: We can do it. Also, when you mentioned opening a fishing school, I definitely pictured fish in a school in front of a chalkboard and someone's writing on that board and little fish in their school seats learning. EDWARD: [laughs] A little Finding Nemo action. STEPH: You got it. [laughs] You know your fishing school. You got to learn to stay away from those hooks. 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 pivoting just a bit on a slightly more technical note, you've been working on a side project called scribe.rip R-I-P. And I've heard a bit about it, but I would love to hear more. Could you tell me more about that project that you're working on? EDWARD: Yeah, sure. So Scribe is what I would call an alternative frontend. And specifically, it is an alternative frontend for medium.com. The goal of the project is to give people a tool to read the Medium articles, not on medium.com, which might sound like a strange goal. [laughs] I'm happy to go into a little bit of a lie there. But that is the tool. And yeah, the domain is scribe.rip, mostly because that was a cheap domain. [laughs] So I got it and put my project there. STEPH: I like that phrasing that you're using, alternative frontends because I think when you had first mentioned that, when I'd heard that in other conversations, I was like, oh, what is that? And I didn't know what it meant. But now, when you put it into some context, that makes all sense. I am intrigued. Why would someone be interested in using an alternative frontend versus, say like, there's an article on Medium; I'll just read it there. What might inspire me to want to use Scribe instead? EDWARD: Definitely. There's a bunch of different reasons. The alternative frontends cover a pretty broad ground. But I'd say the most common reasons that someone might want to use one are privacy if they're worried about the main service, whatever that might be. Let's say Medium, in this case, is doing something with their user data that they'd rather they not do, potentially a better experience on that service. If you don't like the way Medium's articles look, you might want to see them in a different way. It can also be a way to vote with your actions, saying that this is the kind of web that I want to see if you don't like in general what a platform is doing. And if you think a platform is potentially even harmful, it can be a way to say I don't want to support that platform, but sometimes I find myself needing to interact with it in some way. The alternative frontends can be a tool for that. On the very cynical angle, you can also go to you don't want to see ads. And sometimes, these are ad-supported platforms. Alternative frontends can get rid of those ads. And so that's another way too. I'm conflicted more about that one. We can dive into that. But those are the most common reasons I've seen that people want to use alternative frontends. And to be clear, Scribe is not the only alternative frontend out there. There are frontends for YouTube, for Twitter, for Instagram, for Reddit. There's a huge list of a bunch of them, but those are some popular ones. STEPH: Oh, that's really cool. I've never used any of those before. Will be sure to include some links in the show notes so people can check those out. And you listed some really interesting reasons for why folks might want to use an alternative frontend. I'm curious, to make this possible, though, does it mean that the service that is hosting that content do they have an open API into which then you can pull that content? How is an alternative frontend possible? EDWARD: It is possible through APIs almost always. In some form or another, the APIs aren't necessarily open. One interesting side effect to many of the JavaScript rendered apps is that they often talk to some API in the background. And that can often be used to get the content in a more computer-friendly way. And so, with Medium, in particular, they don't really have an open API. So I ended up trying to figure out their API in the background that they're using to fetch articles and was able to get the content and display it in a different way. STEPH: So everything you're describing sounds really interesting. I feel like I do have to ask the question, is it okay that these alternative frontends are taking content and are essentially rendering content but then not using the original service in which the content was published? How do you feel about that aspect? EDWARD: Yeah, it's a really interesting question. There's a bit of a moral argument here, and I think everybody has to make that call for themselves. I think every platform if it gets large enough, is going to have people that don't want it to exist for some reason. I think, in some ways, providing alternative frontends is a bit of a release valve for that platform. Not to say that the alternative frontend explicitly helps that platform, but I imagine it gives people literally an alternative to then use instead and can make a peaceful, neutral ground in a way. So instead of being forced to use only the official platform, you can now use it at least in a limited fashion outside of that, which may alleviate whatever concerns you have and therefore keep everybody happy. And I think honestly, in the long run and in practice, most platforms will not particularly notice the impact of these alternative frontends. Overall, we're talking very, very small potatoes. YouTube is not going after Invidious, the alternative frontend for YouTube, because it's probably a drop in the bucket. Nitter is not getting cease and desist from Twitter. Instagram is not sending a cease and desist to Bibliogram. These are some of these alternative frontends. And I think that's just because it's okay. They don't mind. It's so small. And it's giving people what they want in a way that is not harmful enough for it to really matter in the long run for them. STEPH: Interesting. Because yeah, as you'd mentioned earlier, I think most people are going to continue to use that main service because that's what they see advertised. And it's more well-known, and it's frankly easier to go to. But then for folks who do want a little bit more control over their experience and they still want to access someone's content. So it is interesting. You still want to ensure that the person who created that content always gets recognition and ownership of the content that they have. And in this case, that very much still applies. If I wrote an article on, say, Medium, but then I'm using Scribe to be able to read that content, it's still known who wrote the article. But this way, you are perhaps opting out of something else that service is doing, maybe if they have some type of tracking or something that you're not comfortable with. But you still want to be able to appreciate that person's content, even though they're perhaps only able to publish on Medium for right now. Or they're still looking for more ways to publish their content for folks who would like alternative ways to consume their information. Yeah, it's an interesting spot. EDWARD: Right. And some ways that I think Scribe can provide a slightly better experience are trying to highlight the author more than the platform. The only time it says Scribe on the website is on the homepage. If you go into an actual article, I don't put branding or anything like that. Because I think I really want people to have their work speak for the author, not for the platform, and that's really important to me personally. And that might not be important to you, and that's okay. Maybe you use scribe because it supports dark mode or something like that, and that's totally fine too. I don't mind at all. There are many aspects on which an alternative frontend can provide for people that the official platform doesn't. In some ways, it's augmenting their features, but in some ways, it's just giving people a bit more choice. And I think that's important. STEPH: I have found since you'd mentioned the side project, that I've started using it more to read content. And I have found it helpful because it really silences all the noise because a lot of services want you to see ads, and they do want you to click on more articles that are related to the thing that you're reading. And so, I do appreciate the simplicity that it brings to the content. So then I can really just focus on that one article that someone has written. Overall, it seems like a really neat project. EDWARD: Yeah, thanks. I'm glad you enjoyed it. STEPH: Pivoting just a bit, I would love to go on a slight adventure and answer a listener question with you. What do you think? EDWARD: Yeah, let's do it. STEPH: All right. So this listener question focuses on empathy in your work, and this person writes in, "I'm curious how you all think about and notice empathy from yourselves and others around you. Empathy is so helpful and critical for making and maintaining healthy, productive relationships. I've noticed that the way you frame your client engagements, empathy sounds to be at the heart of them. For myself, I've noticed I'm better at it in certain contexts and certain times and with specific personalities, more so than others. More concretely, how do you stay empathetic with your clients and with cross-functional teams like product or design or even yourself? Can you teach or increase your empathy? And if so, what have you found successful in these situations? So, Edward, this seems really on topic for some of the things that we were discussing earlier. So I'm going to hand it over to you first and get some of your thoughts. EDWARD: This is a really great question. There's a lot to unpack. And one question they asked was, can you teach or increase your empathy, and if so, what have you found successful in what situations? I have found that being vulnerable both publicly and being empathetic publicly is a really useful tool. A lot of teams don't communicate very publicly; it's a lot of stuff in private messages. Being vulnerable publicly in a big team channel can really open the door to letting other people be vulnerable and see what other people are doing, understand what people are feeling. And that's really at the heart of empathy is understanding someone else's point of view. I've also found that starting small, like, just do it with your close co-worker. Maybe try to effect just change with them. And then once you've gotten them on board, broaden it to two other people, and then two more people, and then two more people, because it's really hard to take that leap of faith and be vulnerable by yourself. So I totally get that. And also trying to take this on really early in someone's career or someone's tenure at a job. Offer to help new people to your team. Work with them, so they just start off with a very empathetic experience. And that can grow into a more empathetic team as a whole. Encourage team members to update documentation on their first day because they're learning so much in those first few days. Once they've learned it, the only reason they want to document it is because they have empathy for that next person. And so, just like setting that baseline and that boundary, I think is super helpful. What do you think? STEPH: Yeah, I think those are some great examples. I really love that one way to acquire more empathy is to go on a journey with someone else. So if you have someone new that's joining the team, be their onboarding buddy. Go through that journey with them so you can understand what they're going through, what challenges they are facing. And that will boost the knowledge that you have and will likely also boost then the empathy that you have for people that are new to the team or for future onboarding buddies if you realize that there are some processes that really need to be smoothed out. I also think it's worth highlighting that I don't think empathy is a single skill. I think it's a number of things. It can be the ability to feel someone else's emotions, so you can understand what someone else is feeling at that moment. It could be reasoning about another person's perspective, or it could be just, frankly, wanting to help. So I think there are a number of ways that we can demonstrate empathy to someone else. And it's going to depend on the situation as to which one of those skills is going to be helpful. For how you stay empathetic with clients, that one is a really interesting one just because the way we work with clients; we do get to go on that journey with them. We are with them in making decisions around priority and technical decisions and what pain points they are feeling. So I think going, as you described earlier, going on that journey with someone is what helps us stay empathetic with our clients. And I think that's true for cross-functional teams. So if you are working with someone that's maybe on customer support or on the design team, it could be grabbing lunch with them and saying, "Hey, what's your day like? What challenges are you facing?" Maybe it's your company has rotations where you actually are part of the customer service team for a day. So you get to respond to tickets and have more of an understanding. I'm realizing there's a theme here. I feel like a lot of it comes down to stepping into someone else's shoes and seeing the world from their perspective and not just seeing it but experiencing the world from their perspective. EDWARD: Yeah. And another way to do that...because that can also take a lot of time. It's a hard ask potentially to say, "I'm going to go be a customer service rep for a day," if your job is also, I'm going to be a programmer and ship features or fix bugs. That's hard to do. And I think there are ways to do that, to experience what someone else is experiencing by trying to take on not necessarily the role of the other person but just trying to support the other person in their role. So, for example, we see teams become really siloed where the product is solely responsible for writing tickets, development is solely responsible for understanding what makes the code work or fixing a bug, and design is only responsible for user interactions. I found it really, really helpful to try to approach design and say, "What's the goal here with this user interaction?" I don't know. I'm not a designer. And so, how can I ask them and again bridge my own knowledge gap? Because that can really help you get to that point and help them understand maybe what you're going for and say, "I wasn't going implement it like that because I thought X, Y, and Z." And they go like, "Oh, I see what you're saying." And then now you're making those barriers…or maybe when you're working with products, they're like, "I see what you're trying to do here. But in my experience, I've seen websites like this. How do you feel about that?" And it's not to say that you're just trying to steamroll over them. It's that you're trying to share your experience and get on the same page and trying to get them on your page so that you're all making the decision together, not just handing it back and forth across the wall. STEPH: Yeah, and that was really well said where I think the more that you do collaborate with others and the more that you make decisions with others, the more context you're going to have for why someone else is making a decision, what challenges they're facing. And so again, it comes down to having more information about what that person is going through to then help you be able to be empathetic because I don't think this is a skill you can just turn on. If you don't know anything about somebody, you don't know anything about what they're going through. Being empathetic is going to be incredibly hard. And in this question, they mentioned that they're better at it in some contexts, at certain times with certain personalities. And I think that makes sense because anyone that's more like you, I think you're going to find it easier to be more empathetic. And anyone that has had similar situations, ones that you can relate to, you're going to naturally be more empathetic to. Also, timing is important. Maybe it's the end of the day, and you have already used up your empathy bucket, and you have nothing left to give. And that's just something to be aware of. You may have reached that threshold. And with practice, maybe that bucket will get bigger, and you will have more empathy to give throughout the day. But just be aware when you've also hit that threshold, and maybe you don't have any more to give in that moment. But I do think it's very much a skill that you build with a lot of practice. EDWARD: Yeah, it's absolutely a muscle. You're totally right. You are trying to do it, and the first time you do, it will be very hard. You will be very drained. And you need to recognize that that's okay. You can step away and come back the next day, and it will get a little better. But that's a wonderful point. STEPH: There is a really nice example that you have captured in a thoughtbot blog post that will be sure to link to in the show notes that highlights how difficult it can be to communicate the tone of voice and even how impactful that can be for someone who is reading that message that you have sent, and they don't understand that tone of voice. EDWARD: Yeah, that post was very focused on trying to bring in emotion to a more or less emotionless conversation, which is often text. It's very hard to understand when someone is being sarcastic or angry or bubbly or whatever. Just even silly things like adding emojis can really help in that process of bringing in more emotion and getting that tone across. And I'd say finally to this person who asked the question that the fact that you're thinking about it is already an empathetic thing. Just the fact that you want to get better at this shows that you're already empathetic, and that's really great to hear. STEPH: Yeah, I think that's a really great observation, and I think that's a perfect note for us to end on. So thank you so much to the person that shared this question with us. It is a very interesting question. And I applaud you for being so thoughtful about how to be empathetic with everyone around you. Edward, thank you again for being a guest on the show. For those that are interested in following more of your work or checking out your alternative frontend, where can they find out more about the life of Edward Loveall? EDWARD: You can find the alternative frontend called Scribe; it’s scribe.rip. You can find me at edwardloveall.com. And I have links to various social media or email if you want to email me or whatever. And yeah, it's been a pleasure. Thanks for having me, Steph. STEPH: Thanks so much. On that note, shall we wrap up? EDWARD: Let's wrap up. Ta-ta, Stephanie. 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 in 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: Byeeeeeeeeeeee! 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
Nov 30, 2021 • 42min

317: Burn The Ships!

Steph gives an update about RSpec focus and how she often forgets to remove the focus feature from tests. She figured out two solutions: one using Rubocop, and the other from a Twitter user, suggesting using a GitHub gist. She also suggests that if you're one of those people who misses being in an office environment, you check out soundofcolleagues.com for ambient office noise selection. Chris has been struggling to actually do any coding and is adjusting to doing more product management and shares some strategies that have been helping him. They answer a listener question about dealing with large pull requests and how it's hard to recognize a good seam to break them up when you are in the thick of one. 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. Twitter note re: rspec-retry soundofcolleagues.com mailcheck Inertia.js Svelte devise clearance Become a Sponsor of The Bike Shed! Transcript: CHRIS: One day, I'll grow up. It's fine. I look forward to that day. But today, I don't think it's that day. 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. Well, in some fun news, Utah started his professional training as of this morning, which I'm very excited about. Because we've been working with him to work on being good with walking on a leash, FYI, he's not, [laughs] and also being good about not jumping on people. And essentially, being a really good roommate. And he started training today, and we are using an e-collar, which initially I was really hesitant about because I don't want it to hurt him in any way. But now that I have felt the e-collar myself and we've had a first day with it, it's going super well. I'm very excited for where this is headed. CHRIS: That's very exciting. When does he start paying rent? STEPH: Ooh. I'll have to check with him, or I guess I have set those boundaries. That's my job. CHRIS: I just figured that's a core part of being a good roommate. But maybe we've got baby steps or doggy steps to get there. But that's exciting. I'm glad [laughs] that the first day of training is going well. STEPH: Yeah, it's going great. And the place that we're going to the trainer they have horses, and mules, and goats. And so now I have a very cute video of him trying to play with a goat, and the goat was having none of it. But it's still all very cute. In tech-related news, I have an update for when you and I were recently chatting about the RSpec focus and how I mentioned that I often forget to remove the focus feature from tests. And so then that goes up to a PR, and I have to rely on a kind human to let me know, and then I remove it. Or worst-case scenario, it gets merged into the main branch. And for anyone that's not on Twitter, I just wanted to share an update because I also shared something there. But the resolution for what I was looking for there's already a rule that's written into Rubocop, but it's specifically written in the Rubocop RSpec codebase. And with that rule, you can essentially just say, hey, let me know anytime that a test is using the focus metadata, and then make sure to let me know and fail. And then if you don't want to actually include all of Rubocop into your project because Rubocop is pretty opinionated, you can still add Rubocop to your project, but you can specifically add Rubocop RSpec, and then you can say, hey, all other rules disabled by default, but then you can enable that specific rule. So then, that way, you will catch all of your focus tests. There's also another approach that someone on Twitter shared with us recently from Marz Drel. And Marz shared specifically a really nice simple GitHub Gist that documents or exemplifies that you can add an environment variable that checks to say, hey, if we're in CI mode, then add a before hook. And then that before hook will look for any examples that are using that focus metadata, and then it's going to raise. And then if we're not in CI mode, then don't do anything, don't raise, and carry on. And that's just a really nice simple addition if someone didn't want to pull in Rubocop into their project. CHRIS: Both of those definitely sound like great options. I don't think we have Rubocop on the current project that I'm working on. But I think the RSpec focus thing, the metadata one, seems like it'll work great. More generally, I just want to thank folks out there who listen to the show and then write back in like, "Hey, this is probably what you want." There was a similar thread that someone shared around the RSpec::Retry stuff that I was talking about recently and the failure mode there and trying to get that into the Junit Reporter. And so they had some suggestions around that. Jason Rudolph on Twitter reached out, sharing just his initial exploration and thoughts on how it might be possible to extend the XML reports that are generated and capture a flaky test in that way. So that's really interesting. And again, just really love that folks are listening to the things that we say and then even adding on to them and continuing the conversation. So thanks to everybody for sharing those things. STEPH: Yeah, it's incredibly helpful. And then one other fun thing that I'd love to share, and I found this out from someone else at thoughtbot because they had shared it recently. But it's a neat website called soundofcolleagues.com. And I know you've got your laptop in front of you. So if you'll go visit it, it'll be neat to see as we're talking through it. For anyone else that wants to pull it up, too, we'll include a link in the show notes. But it's a neat project that someone started where you can bump up the sounds that you would normally hear in an office. So maybe you want to bump up background noise of people or an open window. There's one specifically for printers and a coffee machine, and keyboards are on there as well. [laughs] I have discovered I am partial open window and partial rain, although rain is just always my go-to. I like the sound of rain for when I'm working. CHRIS: Gentle rain is definitely nice white noise in general. I've seen this for coffee shops, but I haven't seen the particular one. Also, yes, I definitely know how to spell the word colleague on the first of three tries. Definitely didn't have to rely on Google for that one. But yeah, nice site there. I enjoy that. STEPH: I tried the keyboard option that's on there because I was like, oh yeah, I'm totally going to be into this. This is going to be my jam. I don't think it is because I realized that I'm very biased. I like the sound of my own keyboard. So I had to shush the other one and just listen to the rain and the open window. But that's some of the fun things that are going on in my world today. What's new in your world? CHRIS: I'm just now spending a moment with the keyboard sound. It's a very muted keyboard. I want a little more clackety. STEPH: A little more clackety? CHRIS: I was assuming it would be too much clackety, and that would be the problem. But it sounds more mushy. Maybe we can pipe in some of the sound here [laughs] at this point. Or we can link to these sounds, and everyone can dial up the keyboards to 100. But I, too, am partial to the sounds of my own keyboard. But what's new in my world? This past week and I think probably even a little bit more of the prior week, I’ve been noticing that I've been struggling to actually do any coding, which has been interesting to observe. And again, trying to observe it, not necessarily judge it, although if that's not the thing that we want to be doing, then try and improve that. But mostly trying to observe what's going on, what is taking my time. A lot of it is product management type work. So I am spending a good amount of time trying to gather the different voices and understand what is the work to be done, and then shape that into the backlog and make sure that that's clear and ready for the team to pick up. And then, thankfully, the other two developers that are working on the project are fantastically prolific. So they're often very quickly working through the work that has been set up in front of them. And so I'm trying to then be proactive and respond to the code. But there's almost a cycle to it where I'm just staying out in front of them, but they're catching up with everything that's going on. So it's something that I'm trying again to be intentional about, name, share some of that back up with the group. If there are things that I'm doing that I don't uniquely need to be doing, then let's share as much of that knowledge as possible. But one thing that I will say is the product management, shaping the backlog work is exhausting. I am astonished by just how drained I am at the end of the day. And I'm like, I don't even really feel like I did anything. I didn't write any code, but I am just completely spent. And there really is something to when the work is clear, just doing the work, I can actually find energizing. And it's fun, and I can get in flow state. And sometimes, I'll be drained in a certain way. But the work of taking a bunch of different slack threads, and communications, and meetings, and synthesizing that down, and then determining what the work needs to look like moving forward, and providing enough clarity but then not over constraining and not providing too much clarity. And there are so many micro-decisions that are being made in there. And I'm just spent at the end of the day, and I have so much...I've always had a lot of respect for product managers and folks that are existing in that interstitial space and trying to make sense of the noise, especially of a growing company, but all the more so this week as I've been feeling some of that myself. STEPH: I totally agree. I have felt that having a strong product manager really makes or breaks a project for me where even though having technical leadership is really nice, I'd prefer someone that's really strong at the product knowledge and then helping direct where the product is headed. That is incredibly helpful. Like you mentioned, the work is exhausting. There's someone that joined the thoughtbot team fairly recently, and I was chatting with them about what type of projects they would be interested in working on. And one of their responses was, "I'd love to work on a project with a strong product manager because I have been doing that a fair amount for recent years. And I would love to get back to just focusing on coding." And so I think they enjoyed some of the work, but they just recognize it's exhausting. And I'd really like to just get back to writing code for a while. CHRIS: Yeah, I'm definitely in that space. And I think there's a ton of value to spending a little bit of time, like having any developer at some point in their career spend a little bit of time managing the backlog, and you will learn a bunch from that. But I'm also in the space of I would love to just turn on some music and code for a while. That sounds fun. There's a lot of work to be done right now. I'd love to just be in there doing the work. But sometimes, out of necessity, the defining of the work is the thing that's important. And so, I think I've been correctly assessing the most important thing. And that that has consistently for a while now been the defining and responding to the work that's in process as opposed to doing it myself. But, man, I really hope I get to dive back into the code sometime and use my clackety keyboard to its fullest extent. STEPH: Have you found any particular strategies that really help you with the product management work? CHRIS: I will say that I think this is a competency. This is a skillset and a career path that...again, I've been at plenty of organizations that I don't think respected the role as much as it should be. But it's an incredibly hard role and multidisciplinary communication at the core of it. And so I don't think I'm great at it is the thing that I'll say. So everything that follows is just to be clear; I’m not saying that I'm great at this, but I have been doing some of it. So here are some thoughts that I have. I think a lot of it is in reaction to where I felt like the work was clear. So I have a sense of what it looks like when I can go to the backlog, trust that it is in a roughly solid priority order, pick up a piece of work and immediately go to work on it. And understand what are the end-user implications of this piece of work? Where would I start on it like, how technically? What's a rough approach that I would have? And getting that level of specificity just right. So it's not overconstrained, but it's not under constrained. So having experienced that on the developer side, I try and then use that to shape some of the guidance that I'm putting into, say, the Trello tickets that I'm writing up here. We recently introduced Trello epics, which is I want to say like an add-on. And that allows us just the tiniest bit of product management, like one level up. So instead of just having cards and a list that is like, here's the work to be done, we now have an epics list that is separate to it, and it links between a card and its associated epics. So it's like project and action within that project. And just that little touch of structure there has been really, really useful to help look at like, okay, what are the big pieces that we're trying to move? And then how do they break down into the smaller pieces? So a tiny, tiny bit of fanciness in our product management tool, not Jira-like not going in that direction yet for as long as I cannot. But that little bit of structure. And then thinking about what has been useful to me as I pick up tickets. And then, as always, trying to just always be cognizant of what is the user's experience here? What problem am I trying to solve for them? What is their experience going to be? How will they know how to work with this feature? And just always asking that and then framing the work to be done in the context of that. STEPH: I like how you're adamant about a little bit of fanciness but not all the way to Jira-like. I also like how you highlighted end-users. All of that, I think, is awesome when developers are able to expand their role to experience all the other facets of building software. CHRIS: Yeah, definitely. I think that whole list of all of the different facets of where our work interacts with different groups. The more empathy or, the more experience that you can have there, the better that you'll be able to understand how to communicate there, how to express things in terms, et cetera, et cetera. So a huge fan of all of those ideas. I am ready to just get back in the code for a few minutes, though. But for now, for as long as necessary, I'll do some of this work. But I am trying to find my way to other things. In terms of actual feature work that we're working on, one of the things that we're doing right now is restructuring our onboarding. So when a user comes and signs up to the website and then subsequently has to fill out a handful of other forms, there's actually an external system that we've been working with that houses some of the core data of our application. And they have a hosted application form. So we can send the user over to them, and the user fills out the rest of the application on this other system's site. And then they get redirected back to us. And everything's got nice DNS entries for a particular subdomain and whatnot. So it looks roughly consistent. There's some branding. But it's still someone else's UI, essentially. And we were feeling enough pain from that experience. We were like; you know what? It's time. We're going to bring this back in-house. We're going to do all the forms ourselves. We're going to do a nice progressive little progress bar. You can see all the steps as you're going through onboarding. We're just going to own that more because that's a core part of the experience that we're building here. So biting the bullet, deciding to do that. But there's an interesting edge case that we run into, which is we are using Devise for authentication. Totally makes sense. We're in Rails context; there we go. It's the thing to use. But Devise exists in truly the Rails world. So like HTML ERB templates, the controllers have certain expectations as to what's going on. So thus far, we've just let that exist in that world and everything else we're building in Inertia and Svelte. But we're just now starting to feel enough of the pain, and that Devise exists in this other context. And for a while, we just kept saying, "You know what? It's not worth the effort to port it over. It's fine." Because we're using Tailwind, we have a consistent design language that we can use across them. That said, the components are drifting a little bit. And it's like, oh, this one's got a rounded corner like this, and that one's got this color. And we don't have the disabled style. But it is nice that it's not completely distinct. But we have finally decided it is time. We need to port this thing over because we feel like the onboarding and authentication type flows; they’re actually a big part of the user experience or at least the first run user experience when someone's signing up to our site. So we want to own that a little bit more. One of the things that I ran into as I was trying to introduce Mailcheck, which is a library that I've talked about, I think in a previous episode...but basically, you can have it observe a field and if someone types in like, user@gmaip.com, you can like, did you mean gmail.com? And then go from there. And I think there's more subtlety. They can maybe even look up MX records and things like that. But basically validate an email address heuristically and offer the nice, very friendly to a user, "Hey, did you mean this instead?" So not a full validation that says, "No, you cannot put your email address," because maybe you have a weird one that sounds like Gmail but isn't. But that's a little bit trickier to implement both on the Devise side and then in any other place that we have an email input. And so what we want to do is port over to Inertia and Svelte, and then everything's in our nice, happy context with all our components and all the other work that we're doing. And it really does just highlight how much I've come to enjoy working with Inertia and Svelte. They are fantastic technologies. And now I just want absolutely everything to be in them. So we're finally going to bite the bullet, and I think port those over a little bit after we get the current batch of work done. But soon, soon, that's the goal. STEPH: I'm having a bit of déjà vu where I feel like there was a project that you were working on that was using Devise, and then removing Devise and replacing it with something else was a challenge. Does that ring a bell? CHRIS: Yes, that is accurate. So I had a project that I worked on where we had both Devise and Clearance was actually what was going on. There were basically two different applications that existed; one was using Clearance, the later one used Devise. But then we folded those two applications back together. And by virtue of that, I tried to unify the authentication schemes, and it was like, nope, not going to happen. And then we didn't. STEPH: And then we didn't. [laughs] I like that ending. CHRIS: Well, sometimes you don't. [laughs] STEPH: Yeah, I love that ending because it reflects reality. Sometimes that just happens. In fact, I'm going to segue for just a moment because you're reminding me that there's something I don't think I've shared with you yet. On my previous project, there was a particular feature. It was a big feature that someone had picked up and worked on. And at one point, we were essentially playing hot potato with this feature because we hadn't gotten it to the point that it was merged. There was too much that was happening in that pull request, although then we ended up merging it. But then we found lots of bugs. And it was just one of those features that we couldn't really get across the finish line. There was always something else that was wrong with it or needed to be done or needed to be considered. And we'd reach that point where Chad Pytel, who is on the project, was like, "We're either going to finish this, or we're going to throw it away." And I felt a little guilty saying this, and I was like, "I vote we throw it away. I have lots of concerns about this. We are essentially reimplementing another complex workflow. But now, we are implementing it pretty differently in another portion of the application. It's going to be hard to manage. The cost of adding this and maintaining this is a really high concern." And so he talked with the rest of the team and came back, and he's like, "Yep, we're going to throw it away." And so then he issued a PR, and we removed it. And it was one of those moments of like; this isn't great because then we have invested hours into this, and now we are taking it away. But it also felt really good that that's always an option. And that was the better option because it was either we're going to continue sinking more time into this, or we can stop it now. And then we can move on to more important work. CHRIS: Sunk costs and all that. STEPH: Yeah. I feel like it's so rare when that really happens because then we just feel dedicated to like, well, we're going to make this valuable to somebody. We're going to keep this. And in this case, we just threw it away. It's very nice. CHRIS: There's a similar anecdote that I remember. Actually, I think it's happened more than once. But very particularly, we were working on a system. And this was with our friend, Matt Sumner, a friend of the show, as well been on a few times. And Matt was working on the project. And we got to a point where we had two competing implementations of a given workflow, and we were opting to go with the new one. But there were folks that were saying, "Let's keep the code around for the old one." And Matt was like, "Absolutely not. If we do that, we might go...no, this will be bad. Then we have to maintain that code. We need to burn the ships," as he said. And he actually named the pull request burn the ships where he just removed all the code. And I was like, I like your style, man. You made a decision here. We collectively made a decision. And then this is a classic Matt Sumner move. But he did the thing that we said we were going to do. And he just held that line. And I really appreciated it. And it's a voice that I have in the back of my head often now, which is just like, no, burn the ships. If we need it, it'll be in Git history. We can recover it. But it's going to need to be handled in the interim. We don't want to have to support that code right now and for however long until we actually decide to remove it from the codebase. So let's get rid of it. And if we really need it, well, then we'll resurrect it, but for now, burn the ships. And I like that. STEPH: I like that too. I think it's one of those areas where it takes experience to feel that pain too. If you're pretty new to writing code, you're going to think, well, we can keep it around. There's no harm. And so it often has to be that sage, that person who's been around long enough and felt some pain from making that decision in prior centuries or years. And he's like, "No, we're not going to do this." The WE collective of developers who have experienced the pain from this understand that that's not a good choice. And so we're going to burn the ships instead. But it is one of those that if you're newer, you won't think that way. And I think that's totally reasonable that you wouldn't think that immediately. CHRIS: I think that tacit knowledge that oh, I've gone through this before, and I've experienced the pain, and now let me tell you about that. And let me try and share that with you because there's always the cost-benefit trade-off. Because if that code stays in the codebase, then we know it works because we've kept it around for that whole time. And so there's a nicety to that, but there's a cost, that maintenance cost. And being able to express that well and being able to say, "I've been here, and let me tell you a tale," but do it in a way that doesn't sound overly condescending or explainy or things like that. I think that's a very subtle skill and a very important one, and frankly, really hard one to get right. I'm not sure I always hit the mark on that where I'm just like, "No, can't do it. It's bad." I think it's very easy to end up in a space where you're just like, "No, it's bad." And they're like, "But why?" And you're like, "Because it's bad. Trust me." It's like, well, I feel like you do need to be able to explain the stories, the experiences that you've had in the past, the anecdotes that you've heard, the blog posts that you've read that have really informed your thinking. But I think that is a big part of what it means to continue on in this profession and be able to do the work and make those subtle trade-offs, and the it depends because, at the end of the day, it all depends. STEPH: Or you just issue a pull request and title it burn the ships. [laughs] CHRIS: Burn the ships. Indeed, that is, in fact an option. And actually, while we're on the topic of pull requests, this might be a perfect segue into a listener question that we have. 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: As always, thanks to everyone who sends in listener questions. We so appreciate getting them. They help direct the conversation and give us something to chat about. So this question comes in from Bryan Robles. And Bryan writes in about large pull requests. And Bryan writes in with, "My toxic trait is large pull requests. Any tips on when you get into a place where you're fixing or refactoring something, and it ends up cascading to many more changes than you want it to? I sometimes can go back and break it up. But it's hard to recognize a good seam when you're in the thick of it." So, Steph, what do you think? Large pull requests and finding yourself in them after [laughs] certain amounts of time. STEPH: Yeah, speaking of that knowledge that often comes from experience, this is something that I'm certainly always striving to get better at. I think it does take practice. There are some things that I do that I can share. And I categorize them really into a before, and I guess midway. So there's the before I set sail and set off to deeper waters list that I will think through as I'm starting a new task, and then there's the I'm lost at sea. And then, I need to figure out how I'm going to organize this change. So in the first category, when I'm first starting off a task, I consider what sort of changes need to be made, and are there any obvious roadblocks? So an obvious roadblock may be changing or updating a model that has one relationship, and I need to change it to has many relationships. Or perhaps there's a part of the application that is untested. And before I make any changes, I need to document that existing behavior. And that really falls neatly within Kent Beck's advice where he said, "First make the change easy (warning: this might be hard) and then make the easy change." So I try to think upfront what are some of the small, incremental changes that I can make first that will then make the final change easy? And then I separate that mentally into PRs. Or I may separate it into tickets, whatever is going to help me stay organized and communicate how I'm breaking up that work. And then the other thing that I'll do is I'll consider what's my MVP? So what's my minimum viable pull request? What set of changes include just enough changes to be helpful to users or to other developers? Which, by the way, is also a helpful mindset to have when you're breaking down work into tickets. So, as an example, let's say that I need to fix some bad data that's causing a site to error. So my first step could be to write a task to fix the bad data. And then, step two, prevent bad data from being created. And then probably step three, I need to rerun the task to fix data that was created during step two. But I can think through each of those steps and separate them into different pull requests. And then there may also be the question of well, how small is too small? Like you're saying, what's a minimum viable pull request? How do I know if I am not delivering value? And that one gets a little trickier and vague. But ultimately, I will think, does it pass CI? Is this change deployable? And then I do have to define what value I'm delivering. And I think that's a common area that folks struggle because we'll think of delivering value as delivering a whole new feature or adding complete test coverage for an untested interface. But delivering value doesn't have to represent that end goal. It may be that you added one test for an untested interface. And that's still delivering really great value to your team, same for delivering a feature to a user. You may be able to speak with that wonderful product manager and find what's the smallest bit of value that you can deliver instead of the whole feature set? I think the smallest PR I can think of that I've issued is either fixing a typo or removing a focus metadata from an RSpec test. So that's my starting point. That's the before I set sail. Those are some of the things I think about. I have more for the I'm lost at sea. But what are your thoughts? CHRIS: First, that was a great summary that you gave. So I totally agree with everything that you just said. I think part of the question I would have...So Bryan wrote this in and described this as his toxic trait. So he's identifying this as something that seemingly consistently plagues him. So I would ask, is there a way that you can introduce something? Like, are there natural breaks in your day? And can you ask the question at those breaks? Like, hey, I've been working on a thing for a little while. Is there a version that I could...like, could I close off a body of work at this moment? When you break for lunch, if you go grab coffee in the morning, when you're leaving at the end of the day, use those natural breakpoints. I'm not sure exactly what you mean when you say large pull requests. But if those are spanning multiple days, in my mind, if anything starts to span more than a day, I will start to ask that question to myself. And that's a reflex that I built up over time by feeling the pain of large pull requests and putting it up, and feeling apologetic. And then having my colleagues gently, professionally kindly ask me to break it down into smaller pieces. And me saying, "I really don't want it. All right, fine, fine, fine, I'll do it." And then I do it. And it's one of those things that I never want to do in the first place, but I'm always happy to have done after the fact. But it is work. And so, if I can get better at pulling that thinking and pulling that question earlier in the process, that I think is really useful. Similarly, I will try to, again, as friendly as I can; if I notice someone mentioning the same body of work at stand up for a few days, I might gently ask, "Hey, is there a way that we can find a shippable version of a portion of that of a subset? Can we put it up behind a feature flag and get something out there just to try and keep the PR small, et cetera?" And so gently nudge in that direction. And then I think the other side of that is being very okay with one character PRs. Like, that's it. We changed one character. It turns out we need to pluralize that word, or we need one-line changes are great. That's fine. And more pull requests, in my mind, are better than fewer, larger pull requests. And so really embracing that and having that be part of the core conversation and demonstrating that throughout the team is a way to share this idea. So that's perhaps more in the process or person point of view on this as opposed to the technical, but that's part of the consideration that I would have. I am interested, and I'll bounce back to, Steph, what you were saying of now that you're out at sea, what do you do? STEPH: So I need to react positively to some of the things that you just said because you made me think of two things. One of them is I've never had someone say, "Hey, Steph, that PR is too small. Could you add some more changes to it? Could you do some more work?" I have had people say, "Hey, that PR was hard to review." But even then, sometimes getting that feedback from folks is hard because nobody really wants to say, "I had a hard time reviewing your PR." That's something that, over time, you may become really comfortable saying to someone. But I think initially, people don't want to say, "Hey, that was hard to review," or "There were a lot of changes in that. Would you break it down?" Because that's a lot of complex emotions and discussion to have there. But yeah, I just figured I'd share that I have never had someone complain that a PR is too small, and I've issued a single character change. And then I love, love how much you asked the question of what's the problem we're trying to solve? And so there's this ambiguous idea of a large PR. But what does that mean? What are the pain points? What are we actually looking to change about our behavior? And then how is that going to impact or benefit the team or benefit ourselves? And so, going back to the question of how do we measure this? How do I know I'm starting to break up my changes in a helpful way? We may need to circle back to that because I don't have answers to it. But I just really like asking that question. As for the I'm lost at sea part, or maybe you're not lost at sea, but you've caught too many fish, and the fish warden is going to fuss at you if you bring too many fish back to dock. I don't think this is a real nautical example. But here we are. CHRIS: Was that the fish warden? STEPH: Yeah, the fish warden. You know, the fish warden. [laughs] CHRIS: Sure, I do, yeah. Yeah, I know about that, well-versed in fish law. STEPH: [laughs] Got to know your fish law. If we're going to talk about pull requests, you got to introduce fish law. But I'm actually going to quote Joël Quenneville, a fellow thoughtboter, because they shared a thoughtful thread on Twitter that talks a lot about breaking up your changes and how to break up your pull requests and your commits. And I'll be sure to include a link in the show notes because it's really worth reading as there's a lot of knowledge in that thread. But one of the things that Joël says is get comfortable with Git, and it makes a world of difference. In particular, you want to get really good at git add --patch, git reset, and git rebase interactive. And that is so true for me. Once I have gotten really good at using those commands, then I feel like I can break up anything. Because often when I am helping someone break something up, it's often they want to, but they're like, "I don't know how. And this is going to take so much of my time. It doesn't feel efficient and the right thing to do." And they're probably right. If you don't know how to break it up, then it may take you too long. And maybe it's not worth it at that point. But if you can ask a friend, and they can help walk you through this process, or if you can learn on your own, that's going to be a game-changer because you will start to think about how can I separate these commits? And I can reorder them, and then issue separate PRs, or just keep them in separate commits, whatever process you're looking to improve. In fact, there's a really great course on Upcase called Mastering Git written by someone who is co-host of this podcast. And it has a lot of great videos and tutorials that will help you get really good at these Git commands and then will help you split up your commits. CHRIS: Oh yeah, I did do that. Warning: it's like three and a half hours long. But it is broken up into, I believe, 10 or 11 videos. So you can find just the ones that you want. There's a couple in the middle that I think are particularly useful talking about the object model of Git. Git is weird, unfortunately. And so I spent a bunch of time in that course. Also, thank you for the kind words, Steph. [laughs] But I spent a bunch of time in that course trying to make Git less weird or understandable. If you look under the hood, it starts to make more sense. But if you really want to get comfortable with manipulating Git history, which I think is a really useful skill for this conversation that we're having, that's the only way I found to do it, just memorizing the steps. It's always going to feel a little bit foreign. But once you understand the stuff under the hood, that's a really useful thing for being able to manipulate and tease apart a pull request and break it into different things, and port things from one branch to another, and all those fun activities. Yeah, man, that was a bunch of years ago too. I wonder what I look like in it. Huh. STEPH: I really liked that episode, the one you just mentioned, the Git Object Model. Now that you've mentioned it, I remember watching it, and it's very interesting. So yeah, thank you for making all this helpful content for folks. There's also a blog post that we can include in the show notes as well that is a really nice overview of using git interactive, and rebase, and squash and amend those types of behaviors as well. So will be sure to include both so folks can check those out. And then to round things out, one of the other things that I will do is I will ask a friend. I will ask someone for help. So we've talked about some of these behaviors, or some of these processes that we have are really built up from experience and practice. And you can watch a lot of helpful content, and you can read blog posts. But sometimes, it really just takes time to get good at it. I know, as I'd mentioned earlier, I am always still looking to improve this particular skill because I think it's so valuable. And one of the ways I do that is I will just phone a friend. And I'll say, "Hey, can we chat for a bit? I would like to show you my changes. I want to hear from you if you see something in here that's valuable that you think can be shipped independently, so that way we can get it delivered faster." Or it may be a change that's just like a test improvement or something. And we can go ahead and get that immediately released to the team, and it will benefit them. Or you may want to do this at the start of a ticket. If I am new to a project or when I am new to a project, I will often ask someone to break down a ticket with me if I'm feeling a little bit uncertain. Or just say, "Hey, do you see any clean lines of division here? I feel like there's a lot in this ticket. You're more familiar with the codebase. What would you ship? How would you ship this incrementally?" and have someone else walk through the process with you. CHRIS: Yep, the phone a friend and/or, as always, pairing is a wonderful tool in these sorts of situations. The one other thing that comes to mind for me is part of the question was about sometimes it's difficult to find a clear parting line within a larger body of work, within a larger change. And that can definitely be true. I think there are certain standouts of like is this a refactoring that can be shipped separately? Is this a test change that would be useful on its own? Is there a model change that we could break out and have just that go out? So there's a bunch of mechanical questions that we can ask and say; here’s categories of things that might fit that bill. But to flip this to the other side, the question was asked by Bryan very much as an I struggle with this thing. This is my toxic trait is the phrase that he used, which I thought was really interesting. And that can be true. This can be something that if you're consistently and uniquely within the team producing these giant PRs and then folks find that difficult to review, then I think that is absolutely something to work on. But if this is something that is happening between members like, other members of the team are also finding that they keep ending up with PRs that are bigger than they expected and taking longer and harder to review, there is a question of is the codebase actually in a shape that makes it harder to do small changes? There's the phrase shotgun surgery, which refers to a codebase that is so entangled and coupled that any change requires modifying ten files just to make one small alteration. And I think that's a worthwhile question to step back and ask, actually, is it not me? Is it actually the codebase? It could be both certainly. But there is a version of your codebase is coupled in a way that means that any even small, tiny change requires touching so many different places in the code. And if that's true, that's at least worth naming and worth highlighting and maybe talking about in retro and saying, hey, this feels like it's true. So maybe we start to get intentional about refactoring, and breaking out, and starting to add those dividing lines within the code such that hopefully, down the road, small changes can, in fact, be small changes. So that is the one last thing that I would consider here. Also, anecdotally, this is just a thing that came to mind. As I've worked with strongly-typed languages, systems that have a compiler, and have a type system, and the ability for the compiler to keep an eye on the whole codebase, I've noticed that it's very easy to do this sort of thing where I just start with one small data model change, and then the compiler is like, oh, you got to go fix it here, and here, and here, and here. And I found that because the compiler is your friend and will just point you to all the places you need to make the change, it is very easy to just keep going because some of that mechanical work is happening on your behalf. And it's a wonderful facet of typed languages and of having a compiler and being able to have that conversation with the compiler. But I found that for me, it is much easier to end up in this mode where I'm like, oh no, this PR is way too large. When I'm working in a system that has types, that has a compiler, that frankly makes it a little bit easier to chase down all the places you need to make a change. So that's also a consideration. It's not necessarily a good or a bad thing, just something that I've observed that feels like it's adjacent to this conversation. But yeah, I think those are my thoughts. STEPH: Yeah, those are great points. I've certainly worked on projects where that felt very true where it's a small change, but it would cascade throughout the project. And all the changes were necessary. It wasn't something that I could split into smaller PRs. So checking if it is the codebase that's really making it hard to have small PRS is a really great idea. CHRIS: Who'd have thunk such a little question could get us rambling for so long? Oh, wait, I would have thunk that. STEPH: And so far, reflecting on the things that we've talked about so far, I think I've talked a good game of where I'm saying, "Oh, I identify the seams upfront, and then I organize and create different tickets." And that is very much not the case. That's the really ideal outcome. But often, I am in the thick of things where like you just said...and it's this moment of, oh, I've done a lot in this PR. And how can I break this up? And that does take time. And it becomes a conversation of trade-off, which is why those Git skills really come in handy because then it will lower the cost of then splitting things out for others. But for people that are struggling with creating smaller PRs, I do think it's very fair to ask your team for help. I think it's also fair that if you issued a large pull request and folks have already reviewed it, and it's gotten approved, and someone makes a comment like, "Oh, this would be great as two PRs instead of one," to say, "Awesome, thank you for letting me know. I will take that forward with me, but I'm not going to do it for this PR." I wouldn't recommend making that a habit. But just know that that is something that you can say to someone to say, "I think this one is good to go at this point. But I will keep that in mind for future PRs. And I may even reach out to you for help if I feel like I'm having trouble splitting up a PR." And bring that person into your progress and use them as an accountability buddy. They can be someone that helps you down that path towards smaller PRs. CHRIS: Yeah, I definitely agree with that, although it becomes a very subtle line. Saying, "Thank you, but no thank you," in a pull request or to feedback is delicate. It's difficult. That's a whole thing. But I agree there have been times where I have either been the one making that decision or suggesting that or being like, "We probably should have broken this up. But we're far enough along now. Let's get this merged. And then we'll iterate on it after the fact." One last thing, actually. I thought I was done, but I have one more thing, which is I feel like there's a strong parallel between test-driven development and this question in that, often, I hear folks saying, "I don't know how to write tests upfront. I don't know how to do that. I know after the fact I can write tests, and I can add them after." And that can definitely be true. It can become more obvious after you've written the code how you could then write a test that would constrain that behavior that would interact with the system. But I think the useful thing that you can do there is take a moment and pause there and say, "Okay, now that I have written the test, what would it look like if I had written this in the first place?" Or if you really want to go for it, throw away the code, try again. Start with the test first and then rebuild it. That's maybe a little much. But that thing of taking these moments of maybe you don't know upfront how to break the work into smaller pieces, but then you get to the end, and you have that conversation with someone. And they highlight where some parting lines would be, or you figure it out after the fact. Stay there in that moment. Meditate on it a bit and try and internalize that knowledge because that's how moving forward, you might know how to do this in the future. So take those moments, whether it be with TDD or with pull requests, or breaking up a ticket into smaller tickets, anything like that. And spend a moment there and try and internalize that knowledge so that you have it proactively moving forward. STEPH: You know how Slack has status? I really like the idea of there being a status that's meditating on...and you can fill it in. And the example that you just provided, meditating on splitting up a pull request or meditating on how to write a test first, [laughs] I think that would be delightful. CHRIS: I, too, think that would be delightful. But with that long, adventurous answer to what seemed like a simple question, and they always do, but here we are, shall we wrap up? STEPH: Let's wrap up. CHRIS: The show notes for this episode can be found at bikeshed.fm. STEPH: This show is produced and edited by Mandy Moore. CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in 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.Support The Bike Shed
undefined
Nov 16, 2021 • 40min

316: Constrain and Refactor

Chris finally got his new computer! 🎉 🎉 🎉 He gives his initial review. He's also super excited that GitHub announced a beta for pull requests merge queue, and even more excited that multiple people who listen to this show very kindly pointed that out to him on Twitter! Steph discovered something that is quite niche, but she's excited to tinker with it more, called CookLang. It's a markup language that's designed for cooking and recipe management so you can store recipes and text files and there's no database required; making it easy to have control over recipes versus storing them in a separate application. Then they answer a listener question about refactoring murky legacy code. 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. CookLang – Recipe Markup Language Pull Request Merge Queue Limited Beta | GitHub Changelog After_party - Automated post-deploy tasks for Ruby/Rails Therapeutic Refactoring by Katrina Owen Unused - Identify unused code in Rails, Phoenix, and other types of applications. 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. Hey, Chris, what's new in your world? CHRIS: What's new in my world? Well, we've talked about it before, but it has finally happened. I finally got a new computer. STEPH: Yay, yay. CHRIS: Five years in the making. I held out, I waited. The new computer is fantastic. I'm in that transition phase of trying to set everything up and get it all...the particular thing holding me back is actually this recording and some dongles. I need to live that USB-C life now. Everything needs new connections and whatnot, particularly my external monitor. STEPH: I'm now realizing how old your current laptop is. CHRIS: [laughs] Did I just date myself? Yes. STEPH: You did. You just dated it with a USB-C. I thought you were still on the USB-C life. CHRIS: I'm pretty sure it's a 2016. I'm currently recording on a 2016 MacBook Pro. But yeah, I'm very excited with the new one. The shape of them is weird. I did not expect this because I've seen the 13-inch MacBook Pros that have the touch bar and other things that I didn't really want. But the shape of that laptop was more familiar to me. And this one, I don't know, it's weirder and rounder and bulkier in ways that I didn't expect. And it's heavier than I expected. I got the 14-inch, as an aside. I went with a slightly smaller version assuming that my 16-inch with a giant bezel, because it's from the past, would have a similar amount of screen real estate to a 14-inch with no bezels or with the screen going almost out to the edges. As an aside, the notch in the top of the computer screen is ridiculous. I've dealt with it on the phone for a while now. I accepted that I live in the land of notches. But somehow, it's way, way worse on the computer like when I take my terminal full screen most of the time, and so stuff just gets lost. I don’t know, I got to deal with this or not, maybe I can just not care. But it is covering things that I want to read. And I'm like, well, this is annoying. But yeah, beyond the notch, everything else is great. It's a nice form factor. It seems to have great battery life. It's very fast. It goes very fast. It also has...there's more RAM in it. There's more hard drive space and whatnot, so a bunch of the things that I use. Often as we start this recording I'm like, oh no, I wonder if I have enough hard drive space for the recording we're about to do, which I should probably be past that at this point in my life. Well, now I think I am, except I haven't yet ported my recording setup. Nonetheless, I'm very excited. And particularly, a lot of the development workflow tasks like starting up the dev server of the project that I'm on just moves a lot more quickly. It's a lot snappier, and everything is just speedier. The fans don't really turn on. It doesn't get too hot even when I'm doing challenging things, downloading everything from the internet and compiling from source code. It's like, yeah, cool; I can do that. That seems like a thing that's well within my wheelhouse. And I'm like, cool, computer, good job. Glad to have you on the team. STEPH: So I learned something about you recently because hey, we were hanging out in person recently since I was in Boston for a week. That was amazing. And I learned that we have a similar thing where we both like to start our machines from scratch, and slowly (or at least correct me as I'm going through this), we bring things over. But it's not an immediate just port everything from my current laptop over to my new laptop. And I'm fascinated because I thought I was the only one with this sickness. But it turns out that you, my friend, also have this in your life. CHRIS: Well, yes, you are correct. That is the thing that is true. And also, to reiterate, it was really lovely seeing you in the human world as opposed to just in a Skype window as we so often do. But yes, I start fresh every time. But to be clear, it's been more than five years since the last time I did this. So I feel like I can make a bit of an event of it each time I do it. So I'm fine with that. But I do like starting from fresh reinstalling everything rather than trying to copy over an image of the system. I felt a little bit shamed by the operating system because there's the like, welcome to your new Mac. What's your language? What's your WiFi? What do you want to migrate over? And I'm like, nothing. But there wasn't a button for no, thank you. [chuckles] There were buttons that were like...there were two different options, but neither of them were no. And I'm just staring at it, and I'm like, but I would like to not though. I would like to just start fresh. STEPH: [laughs] CHRIS: And I got it from here. I appreciate the effort. Turns out they were hiding it in the bottom left corner, but it wasn't a button. It was like link text, but it was barely emphasized. And on the right were where all the action buttons for every previous step and subsequent step were. So this was like no one would ever want to do this. So we're just going to hide the option over in the corner. Yes, I very much like starting fresh. I like to get the chance to shed some of the mistakes of the past and only bring forward the things that are bringing me joy in the modern-day, so here we are. A lot of stuff doesn't work, by the way. [laughter] I brought over my dotfiles, and things did not work super great. Or I opened an application, and it's like, oh, that hasn't worked for years, and I'm like, I was living in the past. All right, this is fine. I'll update my workflow. It'll be okay. STEPH: I like how you said make an event of it because I haven't really found the right words for it, but that's perfect. I have a fresh laptop, and it's an event, and I want to spend that time setting it up and shutting the mistakes of the past. [laughs] That too, that also resonates. CHRIS: Yep. It's really about the mistakes of the past. I don't want to live there anymore. I want to move on from them. But overall, yeah, it's going well. I think I'll be able to work with it. I'm actually unfortunately limited in that I can't connect it to my monitor right now or to the keyboard that I have and whatnot. So I can't quite integrate it into my home office setup. I can use the laptop itself, and it's working fine. I've got my current project running on it. So I was able to install Ruby and figure out how do I trick it into using the Homebrew things versus the M1 things versus which architecture and yadda yadda yadda? That actually went better than I expected. I thought it was going to have more issues there, but stuff just kind of worked. And I had to find one weird Stack Overflow and copied and pasted as one does when you're setting up new computers or all the time as a programmer. And then yeah, we're off to the races. But yeah, unfortunately, right now, the limitation is a physical cable. I need a couple of new cables. So I'm excited to get those in the near term. STEPH: Yeah, that'll be nice to have it set up and feel like you can fully transition to the new setup. CHRIS: But in slightly other news, so computer is great, very happy about that. Perhaps I’m even more excited that GitHub has announced a beta for pull requests merge queue, and even more so excited that multiple people who listen to this show very kindly pointed that out to me on Twitter. And I was like, this is the dream. I just rant about stuff on a podcast, and then people tell me when the world has solved the problem that I complained about. This is so great. But it's a public beta, but you go on an invite list and whatnot. So I'm on that list right now. And I'm trying to just mention it as much as possible, especially near any friends I know that happen to work at GitHub; just be like, "Hey, if you happen to know how to find that list...and I will give wonderful feedback. I will be an active member of this beta." But I would really love to get to try out that feature. So I'm excited. We'll include show note links to the blog post announcing this new feature. So I'm really excited that it is built into the platform and will sort of be there. And I'm hopeful that GitHub has done a great job. This is actually a really interesting feature in my mind. It's one of those things like, oh, it's pretty straightforward. You just make a queue, and then you merge things. It's like, oh yeah, but what about all the ways it can go wrong? It's a great I think iceberg feature where the simple, happy path is wonderful. And then there are so many different failure modes like, oh, what do you do when the PR fails to rebase? Or should you proactively rebuild the sequence of them? Do you stack them up and start preemptively rebuilding the other PRs that are next in line in the queue after that? But what if then it fails? And et cetera, et cetera. There's lots of fun stuff that can go wrong. So I trust that GitHub will do a wonderful implementation. I would love to get to try that, but currently, I've yet to get in. STEPH: Have they shared how to get access to the limited beta? Is it just random selection, or can you specifically request? It sounds like you can't, based on what you're saying, but I'm curious. CHRIS: There is a waitlist. Particularly, they had me put the repo that I was interested in, so like, I would like to be in the beta. And this repo, in particular, is the one that I would like to put into the beta. So I've submitted that, but now I'm just in a list. I don't know where in the list I am. I have no visibility into that. So again, I'm just saying things out into the void and seeing if the universe then reflects anything back at me, and by that, I mean people that work at GitHub. Hi, friends. STEPH: I totally believe that if you speak things into the universe, the universe will give that back to you, or that's probably not true. So here's hoping that you get into the beta list. CHRIS: Here's hoping. One other tiny thing I have been using Afterparty a bunch lately, which is a gem that you have recommended to me, I believe, in a previous episode not that long ago. But we started doing feature flags. Feature flags are great. We're using Flipper. It's wonderful. But Flipper stores...the way we've configured it, we're storing them in the database. And so, when we get to the point where we want to fully release a feature, we dial-up so that everyone has access to it. So at this point, the feature flag system is still running, but everyone is getting access to that feature. And so then there's a code change that removes any references to the feature flag, any checks for it. And subsequently, we want to then clean up after ourselves. Afterparty has been fantastic. I'm really happy with the way that that works and that we can just include the Afterparty data migration associated with that, delete the record from the database, and then everything consistently works together. This does poke at the edge, though, of how Heroku does deployments and the fact that there is that latency where it will basically restart with the new code, needs to run all migration steps, et cetera, et cetera. And then it's running on the new code, which is great. That's what I want in this case. But it does have a cost, and I would love to figure out true blue-green deployments sometime in my usage of Heroku such that we can have zero downtime deployments is actually the way to phrase it. Using Afterparty for this, I think, is leveraging the idea that it's not a big deal. It'll be fine. Because if we had zero downtime deployments, I think temporarily, we would be in a space where feature flag has been deleted; therefore, no one is in the feature. Therefore, no one would see it for that weird second. I'm safe from that. But it's this weird trade-off that I have in my mind of I want blue-green deployments, but I'm appreciating that I don't have them right now and that there is a consistent...and I think that's the reason that Heroku makes the choice that they do. But, man, everything's complicated. Why can't stuff just be simple? STEPH: Everything is complicated. So I'm thinking back through to now my previous client's setup since I'm about to transition to a new project. And we have AWS. We have rolling deploys, so we don't have that specific downtime. We are using Afterparty. So I think based on everything that you're saying that yes, there's a slight period of where we are rolling out a feature flag or potentially dropping it, and that could put some users into a weird state if they're active and then the code suddenly changes. I'm thinking through out loud and singing it because apparently, that is what I do. We haven't run into any issues with that. But I am now trying to think through of when someone might end up in a weird state because of that. CHRIS: You almost certainly won't run into any issues because we're talking about a matter of seconds where the code is in an inconsistent state. But the same thing applies to migrations like database migrations where if you're doing rolling deployments and the database migration hasn't happened yet, but there's new code that's running that expects that database state, then you're in this subtly inconsistent mode. And I think if you really want to adopt this idea of rolling deployments or zero downtime deployments, you have to separate data changes from the code that uses that data change such that both versions of the code when the migration goes out are fine. And then later, you deploy the code that uses the migration, but then that's like a whole bunch of more steps. And you got to think about it, and you have to probably put in some pull request review step to check on it. And so again, it's just complicated. STEPH: So that's one of the reasons we did change our feature flag implementation was because we realized it was a pain. Because anytime that we wanted to drop feature flags, we first issued a PR that removed any references in the code to that feature flag, let that deploy. And then we'd issue a separate pull request that went out in a different deploy that went and dropped that column. So that way, we didn't have any situations where maybe ActiveRecord has cached to that column, and then there's code that's looking for it, but then it's not actually there. And then you run into that funkiness and complicated behavior. So we were at a point where removing a feature flag required two PRs and two deploys, and that was awful. So we switched up how we were handling feature flags specifically so we could avoid that and started storing them in JSON files because we took the more bespoke approach to feature flags versus using Flipper. CHRIS: Bespoke artisanal feature flags. STEPH: I don't know that I'd recommend it. It's working. It's been a journey, and there are things working well about it. But it's definitely still in that space where it's like, I'm a little uncomfortable of like, how far should we go in this bespoke world and at what point we should reconsider and use something like Flipper. I would say stay tuned, but I'm not on that project anymore. So I'll just never know. [laughs] Sounds like a devious laugh. I will know probably from some friends that are on the project, but I won't be there for it. [laughs] CHRIS: Cool. Well, yeah, I think that sums up things in my world. What's new in your world? STEPH: I have discovered something that's quite niche, but I'm excited to tinker with it more. It's called CookLang. And it's a markup language that's designed for cooking and recipe management. So you can store recipes and text files, and there's no database that's required. So it's easy to have control over your recipes versus storing them in a separate application, which is currently how I store my recipes. Which for the record, I'm happy to pay for software. I am very appreciative of when people make my life easier. And so I very much enjoy that. But I also still love the it's mine, and I can just have it stored somewhere in the cloud, and I'll never lose it. And I don't have to worry about renewing memberships to keep access to something. So there's a part of me that is very drawn to the idea that I can just have everything in the text file. I can store it anywhere that I want. And then, for this particular CookLang markup language, it lets you define certain qualities of your recipe. So you can define the ingredients, the quantity, cookware, timers. It'll help you create shopping lists, and you can set metadata. So maybe you want to include the total prep time or the type of meal, or the number of people that the recipe serves. And they also have an iOS app that is in beta. So speaking of beta, this one is closed at the moment because they've had a pretty overwhelming positive response or interest. So they have shut it down for now in terms of accepting new people to the beta; at least, that's my current understanding. But the iOS app does look like it'll be really nice. It's going to read from your files; I think stored in iTunes. But I'm just excited for all of this. It looks very interesting. And it looks like something that's just fun to play with. So I haven't moved anything over to start really investing and creating these .cook files that you use for the cook language. But it all seems very cute, very niche, and something I'm totally into. CHRIS: I have not seen this, but it looks absolutely fantastic. I'm just reading the brief syntax snippet that they have at the top and the way that they're inferring semantic meaning from plain text recipes. And then you can generate a shopping list, super cool. You can just be like; I’m going to cook these things from my recipes. And then they'll tell you the shopping list, and it's grouped. And this feels like what software should be in my mind. This doesn't feel like we're going too far with it, which is very easy to do. But it's like, no, no, we've annotated just a little bit of semantic meaning on top of something. And then with that, we can do wonderful things. Look at all the good stuff that falls out of it. We can have an iOS app. We can generate shopping lists. It's great. But it's also minimal and contained, and not locked in a proprietary format. And this is fantastic. STEPH: There's also the nice part where they've already started highlighting that people can just store their recipes on GitHub. And then you can just fork recipes, or you can import everybody else's recipes. And I love that. I want more open-source recipes, although frankly, there are tons of just free amount of work and recipes that people have on the internet. But I love this because then I could skip all the ads that go with it. And I can just grab the stuff that I care about. CHRIS: You mean you don't want to hear the person's life story before every single recipe. You don't want to hear about the walk that they took along the river when they were thinking about seasonal gourds, and then they decided to make a particular -- [laughs] STEPH: [chuckles] I would normally...previous Stephanie would have been snarky about that in regards to all of that backstory that's given for a recipe. But then I saw somewhere maybe a friend was telling me about someone who had asked, "Why do y'all do this? Why are you putting so much information? Why can't I just have the recipe?" And they're like, "Well, frankly, Google's going to rank us a lot higher if we give you this whole backstory and if we look like there's more content to this page than just a recipe." And I'm like, dang. Okay, so it's Google that I have to be snarky about because they're doing their best in terms of trying to get you the recipe that you care about and make it very searchable. CHRIS: Oh, yes. Absolutely. It's both a self-imposed problem. But also, I don't think Google's doing anything wrong here either. Google's part of their algorithm is they penalize duplicate content. And so there's what they view as the canonical source, the thing that's telling the truth. And then recipes look very much the same because they are kind of the same most of the time. This is how you make bread. This is also how you make bread. Two people now have almost identically the same content on the internet. And Google will penalize one that it determines to be copying essentially, which I think is a good thing broadly. I've seen so many Stack Overflow...I want to say clones, but they're not even that. They're just literally taking the content and then republishing it entirely new. And that is a very bad thing that happens constantly and takes away from creators and whatnot. And so, in a way, Google's trying to do the right thing here, I think. But it leads to really just so much summary about recipes. It's one of those weird...is this a tragedy of the commons? I don't know. I've never quite understood that one. But I think it might be. STEPH: Yeah, I don't know. That's my off-mic answer. [laughs] CHRIS: That's fine. Someone on the internet will tell me whether or not this is a tragedy of the commons. But either way, I do not blame the recipe authors. I do not blame Google? You'll note the question in my voice. But I think I stand by that. I'm not sure who to blame. Maybe it's us. But here we are. [laughs] STEPH: Yes, I like that final takeaway of let's not blame the people that are trying to give us wonderful, helpful content. Circling back a bit to some of the code that is powering CookLang or some of the interesting bits about CookLang, for anyone that's interested, you can also visit the GitHub repos they have. I believe everything is open source. There's a particular repo called spec. And you can view the issues, and you can see all the conversations around how should we annotate an ingredient? Or should we have comments in the language? And how should we handle this type of metadata? And I find that interesting because I haven't really participated in any of the language crafting forums for Ruby or some of the other languages that I use. So it's neat to watch how some of this is being done in public to say, hey, we're just making this new markup language, and we're not really sure how we want to annotate everything. So what do people think? What's working for you? What's not? And I'm enjoying that conversation and reading along. CHRIS: It really is such an interesting microcosm of an example of a language, an ecosystem, a community, a specification, and all of the stuff that is true of all of the other languages that we use more generally. But I'm looking down here, and there's the parser implementation. There's a Swift canonical parser. But then Rust, somebody is rewriting this in Rust because, of course, they are. But you know what? It's going to parse your recipe so fast, and it's going to be great. [laughter] But it does have the shape of everything that I've seen from other programming language conversations. And how do we evolve the language, and what syntax do we accept versus what do we not? And this is so interesting. STEPH: Yeah, it's really neat. I'm really into it, and I'm really enjoying it thus far. 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, changing gears just a bit, we have a listener question that frankly is a doozy of a listener question. It's a bit long, but I feel like all of the content in here is important. And I feel like most people are going to be able to relate to this scenario that the question is describing. So this question comes from Michael Kopinsky and Ben Rosenbach from Philadelphia. And they write in, "There's one area of our codebase which has a lot of skeletons." I'm already empathizing. "The UI is error-prone jQuery soup, and the UX doesn't entirely make sense. Test coverage is close to non-existent. And the expected behavior isn't clear and has lots of edge cases. We've thought over the years of how we can redo it, but it's never a priority. Redoing it would be a huge lift, and...it works usually. We get bug reports occasionally, which inevitably get closed as won't fix workaround provided. But a few months ago, we received a bug report, and I decided to start cleaning things up. I opened a merge request with a set of factors extracting some behavior into a service object, making explicit some things that were implicit and adding test." Side note, that's some hero work. I appreciate that right there. "It's gone through a few cycles of code review and pairing each time suggesting additional cleanups to do, requesting additional test coverage and that sort of thing. But the more we do, the more we discover that needs to be done. So at this point, the merge request has been open for about eight weeks. I've paired with two other developers for probably 12 hours. The user is impatient, and we're tired of this darn thing and want it to go away. But it feels so bad. It really is severely lacking in test coverage. And the expected behaviors still aren't clearly defined. And it just doesn't meet the normal quality standards that we try to hold ourselves to. We could sit for another 8 to 40 hours and write more tests or documentation, but we're so drained from this whole thing. So overall, we're really struggling to balance two things. We want to get things out the door, have short-lived PRs, and focus on incremental improvement. However, we still don't have defined requirements of how the feature is supposed to work across all permutations. And we can't write proper tests until expected behavior is defined more clearly. It feels like that's a baseline requirement before being able to merge or refactor. We'd love to hear any thoughts. Sincerely, Michael and Ben." Ooh, friend, there is so much we can dive into here. Would you like me to get started, or would you like to start? CHRIS: Yeah, I've got a handful of thoughts because, as you highlighted, this is all of the stuff. This is the murky pile of complexity that writing code and delivering value in an organization is made up of. I'm going to start at a random place and then just start saying things because I think there is not a singular answer to this is an important starting line. We're not going to say, oh, if you just did X, then it would be fine. Obviously, this is a number of different complexities and situations, both person or both interpersonal human, and then code, and et cetera, et cetera. So one of the things that actually came in the latter part of what you were reading there is we do not have defined requirements as to how this feature is supposed to work across all permutations of how it can be used. And that one is really interesting to me because right now, I wonder if there's something that can be done there. So often, you have code that does some stuff but also could do other stuff. And it's not clear if it's actually intended to do that other stuff or if that's just something that falls out of overly permissive like, we'll take any data you throw at us, and then we'll do some stuff. Typically, we don't actually want that. We want a more constrained system that's doing something. So that particular part was really interesting. Some of the conversations about testing were really interesting. I think one of the things I would do is I would really ask, is this worth the effort? This code is kind of doing its thing. It's been around for a while. It's business-critical, but nobody really understands. It's like, is there a version of just leaving it at rest? Probably not. I typically would not do that. But it is a question that I think is worth asking because it can be really hard to make these changes on an under-defined system written in legacy technologies and whatnot, especially ones that we don't necessarily have as much...like, I haven't worked in jQuery for a while. So I wouldn't be quite as good at that. I wouldn't be able to understand that code as intuitively. That might be similar for this team. So is there a version of just letting it lie? That is the first question I would ask. Presuming that's not the case, then I think I start to look at what is the attack that I would take to approach this. And I would definitely start with, hopefully, some small but meaningful introductions of test coverage but as a standalone thing. It's not part of the big change of a pull request. It's merely trying to lock in the code as it exists. Again, I think I've referenced this talk perhaps more than any other, but Katrina Owens'Therapeutic refactoring is a really wonderful story and talk and really talks through this idea in a great way, but also it's just fun watch. But in it, Katrina talks about her approach to a similar thing where she was like, there's some code, and nobody really knows what it does. So I'm going to try and lock it down. And the first thing that she does is wraps test coverage around this code. So at least whatever it's doing now, we've constrained it a little bit. And actually, via the testing that she does, she ends up using that as a mechanism to sort of what does this system do? And finds a way to exercise the system and determine what its behavior actually is because nobody really knows that at this point. So I would start with the testing. And then I would ask the question of we don't really know what it does across all permutations. Is there a way to actually constrain that? And say, let's actually lock some stuff down. Let's add a tiny bit of code that looks at the inputs being requested or coming into this code path or whatever it is but actually explicitly delineates what we think is the expected inputs and rejects or at least logs things that are surprising and that are like, we don't think it should do any of this. And then suddenly, if you see that showing up in the logs, you're like, I guess it does need to do that. Now we have a better idea of what is the actual target that we're trying to hit. But really, both of those in my mind are ways to try and constrain the problem to try and add a little bit of support before tackling the hard work of the refactor because, just to be clear, you're probably going to break it in the refactor. I've broken every single system like this that I've tried to refactor without question. And there's a certain amount of organizational trust that you need to have. And it just gets to be a very complex time. And so anything that I can do to provide some guide rails, some support, something to help me in that time is something that I'm going to start with before I even go near the refactor itself. So those are some thoughts scattered around throughout the question. What do you think, Steph? What comes top of mind for you as you hear this question? STEPH: I think those are great thoughts. And to expand on what you're talking about determining the expected behavior, that's also one of the bits that jumped out to me. And I love that you asked the question, can we leave it at rest? It sounds like yes, but there are some user concerns that come through or some bug reports. And then the team has to collectively say, "Yes, we are going to put someone through a difficult time to either do maybe a gross fix or implementation." And then we're making this area of the codebase feel worse and more accepting of different flows and adding to the number of flows that we have. Or we document it as won't fix and then provide a workaround. So I really like that you said, "Can we leave it at rest?" Because I think that helps a team make a decision together as to like, what is the understanding of this part of the codebase functionality? How important is it to the business? If we decide that it's not that important to the business, then it's frankly not worth anybody's time working on it even if it feels really bad and you know there's this gross code over here, and you really want to go work on it. But if it's not important to the business, then it just shouldn't be done. And it needs to be left alone until the business decides this is important to our functionality. We do want to prioritize this work, and we're going to work on it together. And I still think there are a couple of nuanced strategies even from there. So if you're looking for the more incremental improvements of we can't totally let this lie...we do have to improve it. But we're also not willing to invest in an overhaul situation. So some of the incremental improvements would be, as you'd mentioned, adding some test coverage to it to at least start to lock in the behavior that's already there and establish a baseline of understanding and then document that behavior. I've also found that really helps for context switching. So if you go in and you just document one part of that system as something that it does, then it frees you up. You can add something. You can issue a smaller merge request. You can get that merged because you're just adding test coverage. So it's not going to break anything. You're not making code changes. But then you can nearly let that go. And you can jump to something else that the team or the business has decided that's more important. Some other areas that I've used in the past for working in these types of legacy or just bug-prone areas is to look for flows that are no longer in use. So if there's something that stands out to me as like, I'm pretty sure users aren't using this, or this code just looks unused. Maybe it's running a tool like Unused, which we can link to in the show notes, and see if there's truly something that's unused that you can just immediately remove. Or maybe it's logging a message to Rollbar or something similar. So that way, you know this is actually being used, but you can have it log whenever that's being run. Let that live for a month and then go back and check to see if that flow is ever executed. As for the larger overhaul approach, that really has to be a team effort. So this has to be one of those moments of like the company decides this is important. And there may be smaller wins you can look for, but I do think it's going to require at least a developer or the product manager to be invested and ideally a designer as well. And then some small steps there may be looking for reducing responsibility of that feature. So maybe it's this really verbose long form that's complicated. And maybe you can collect some of that information somewhere else in the app. So you can start to chip away at some of the responsibilities in that portion of the application. Or maybe you have a mini design sprint. You may realize this is a very important part of your application. We should really have this be a better experience for users. And let's really take a hard look at what this does and start to document. And that's the bigger like we're going to rebuild this, or the whole team is going to focus on this and improve this portion of the application. So that was in response to some of the lovely things that you said that you made me think of. The other thing that really jumped out to me is this merge request that's sitting because this person, Michael or Ben, they've already done some really hard work where they have decided to add test coverage. They've cleaned up some things. And I can certainly relate to you issue a pull request and someone...because you've started cleaning up a space, people are like, "Oh, what about that cobweb? And then you missed a spot. What about over here?" And so, how do you make progress when you're in that state? And I would say move the goal line and merge the pull request. So your goal line sounds like right now is trying to address everything which doesn't feel humanly possible. So instead, move the goal line. Figure out okay, I just want to add these couple of tests, or I just want to add this refactor to a function or something that documents this part of the system. And if people are nervous about merging the current merge request because it has gotten so big and people have made so many small requests, is to then break it up into smaller, more focused PR. So then it makes it easier for people to say, "Yes, that does improve the state of this codebase. Please merge it." And I will often prefix my PRs with that. I'll say, "Dear reviewer, this PR is intended to improve the state of the world. It does not improve everything because I can't, but this is the goal of this." So that way, people go in with the mindset of they'll realize they're still going to see some cruft. But this is still leading us towards a better place. And unless there are strong concerns about the changes made in that specific PR, any other requests need to be noted and then can be captured somewhere else, but we're not going to address it right now in this PR. CHRIS: I agree so very much with all of the things you just said. For anyone at home who cannot see us on the Skype call that we're on, I was just aggressively nodding my head the entire time Steph was saying all of that. [chuckles] You touched on I think all of the additional points that I would want to make specific to this merge request is out there in the world and whatnot. The one other tiny bit that I would add to it is I have definitely been the person, and then I've also been on the other side of it where people get attached to the code that they've written. "But I've already written the merge request." And you're like, "Yeah, but can you break it up?" And they're like, "Yeah, but it already is a thing. And I did a bunch of work. And now I'm emotionally invested in this pile of work getting across the finish line and breaking it apart..." We can get caught up in our code. And this is a really great example of this thing just got away from you. This is too big of a refactor. It's too much of a risk. And so again, I have struggled with this personally where I'm like, I'm so proud of this pile of work that I just made. And people are like, "Yeah, but that's a big pile of work there." I'm like, "You're right. You're right. I should break this up. I will break this up." But I can feel that resistance in myself to doing that, what feels like extra work, what feels like almost undoing of work. It's like, "No, no, no. I think it's ready." I'll be like, "I don't know, I'm not convinced. Can we break it apart?" And that's almost always the right decision. But it can be painful. And so, just knowing that and having that in the back of your head as a thing that my brain will tell me the opposite. My brain will be like, no, no, go with it. It's great. We're proud of this. But being open to the idea that breaking things up is good, smaller pieces are good, et cetera, et cetera, can be a useful psychological aspect of this conversation because,, of course, there's one more facet. There are so many facets to this question. STEPH: I like that anecdote about that you haven't regretted breaking things up because I also relate to that where there's that initial like, I've already done this much work. And now you're asking me to do more work. And it's going to have the same outcome where it's still going to be the same code. It's still going to be the same set of changes, but you're asking me to break it up into smaller changes. And I just feel exhausted from this work already. And I don't want to have to break this up. So I understand and relate to that initial resistance. But I also really like the idea that all of these changes and everything going into the codebase is managed by a team. So we really want there to be a level of comfort from the team that this is what's going in. And as the author of the changes, I am far more comfortable with everything that's about to get merged in because I've spent so much time with it. So for me, whenever I do feel that initial resistance, I have to ask myself, well, what's the value? Will this make it easier for folks to review? Maybe it will show some areas that I didn't add test coverage because it felt like it was already getting so large. And so I started to negotiate with myself as to like, well, maybe I don't need to test that because this is already getting so big. And I don't want to add more to it. So I really think through what's the value of if I break it up? And will it make the team more confident in this change? And ultimately if it does, then to me, that's always a resounding yes. So it's just going through what's the value versus what's my initial oh, this is a waste of my time to oh no, this is a good use of my time because it really benefits everyone else. Circling back to something else that was said in the question was the message that we're just so drained from the whole thing. And I really don't want to take that for granted because that's really important. And it sounds like someone has taken their own time and hopefully company time to work on this. But it's not a team initiative. So this does feel like one of those areas where it feels like the team needs to prioritize whether this gets worked on or not. And it's okay if the team says, "Yes, this is important, but six months from now because we need a break from it." But as long as it's something that the team worked on together to say this is important, or it's not, I feel like that's an important part. And also to recognize that we don't have to fix all of this right now. That's really important for the company to buy into it. I have two small things that I want to add, sort of the what not to do because we've been talking about some things that we would do. And so one thing that I definitely wouldn't do is avoid having one person going off and trying to fix this part of the codebase. Don't have one person, either a designer, developer, just a single soul who's like, I can fix this, and tackle it, and define all the things, and improve it. That's going to go poorly. Don't do that. And then also, I would avoid refactoring just to refactor, which I think goes a little bit against Therapeutic Refactoring, which is a talk that I absolutely love. But if we're really invested in proving this part of the codebase, then I think it is very helpful and important to have a fixed user deliverable goal driving your refactor because that's also going to help shape and influence your PRs and encourage the team to take the time to review those PRs and get them merged. So there's a nice coupling there where you want something driving that goal. Granted, it could be different for different teams. Therapeutic Refactoring may work wonderfully. But I've just seen so many people sink a lot of time into something, get very frustrated, then nothing gets shipped. So I would favor leaning more until we have this very focused thing that we're going to deliver, whether it's adding a test or two tests. Have a goal in mind when you start that refactor. CHRIS: Again, I find myself nodding aggressively with everything that you're saying. And in addition, I really like the subtlety that you're bringing to one of my favorite talks. I've mentioned many times that this is one of my favorite talks. But I think you've added a really interesting like, yeah, but also, in the way that everything depends, it also depends. And I think you framed that really well that refactoring for refactoring sake can be fun and therapeutic, and cathartic for an individual. But we have to make sure it's part of the overall work that we're doing. And you've now, I think, really well captured the human side of this work that is captured in what is such a complicated, nuanced question that I think also does such a good job of just highlighting the work. This is what it looks like. This is a particular almost perfect storm of the work, but that happens. But each little piece of this that we've talked about is this is the day-to-day of software development interestingly. I always thought it was just going to be writing for loops. I haven't written a for loop in years. I don't even know how to write a for loop. But this stuff is what I do every day. [laughter] STEPH: The most challenging part for me in software I realized is when a problem has escalated to the point where it's like, I can't just write code to fix this. I need to go to the team. I need to get buy-in. And that's where I start to realize this is where software to me really gets hard because then I need other people to contribute and to get their opinions. And it turns out way better for it. But yes, that is definitely the intersection for me where I can write code up to a certain point to then I really need people to help make really great software and fix some of the underlying issues that we're facing. On that note, Michael and Ben, thank you so much for writing this in to us. I'm very interested to hear how this turns out for your team. And thank you so much. I wish you the best of luck. 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 in 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: Byeeeeeeeeeeee! 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