323: Doing Things
The Bike Shed - A podcast by thoughtbot - Marți
Categories:
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 [email protected] 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