
The Bike Shed
On The Bike Shed, hosts Joël Quenneville and Stephanie Minn discuss development experiences and challenges at thoughtbot with Ruby, Rails, JavaScript, and whatever else is drawing their attention, admiration, or ire this week.
Latest episodes

Oct 17, 2023 • 23min
404: Estimation
In this podcast, Stephanie and Joel explore the challenges of providing estimates for projects, the importance of acknowledging uncertainty, and the need for clear communication and transparency. They also discuss Joël's acceptance to speak at RubyConf in San Diego and the different aspects of time he will be discussing. Additionally, Stephanie reflects on her recent experience giving estimates without enough information. They touch on the concept of creativity, embracing change, and the use of placeholders in software development.

10 snips
Sep 26, 2023 • 38min
403: Productivity Tricks
Stephanie and Joël discuss productivity tricks, including Kent Beck's Substack, debugging assumptions, keyboard shortcuts, apps like Alfred and Rectangle, Vim plugins, and strategies for focus and energy management.

Sep 19, 2023 • 38min
402: Musings on Mentorship
Joël and Stephanie discuss old-school object orientation exercises, mentorship in one-on-one and group settings, a new mentorship initiative at thoughtbot, and the importance of sharing perspectives and experiences. They also talk about transitioning from urban biking to nature biking, challenges faced by principal developers in balancing team contributions, and exploring peer mentorship through platforms like Exorcism.io.

Sep 12, 2023 • 31min
401: Making the Right Thing Easy
Stephanie shares a debugging mystery, Joël talks about his bookmark manager. They discuss streamlining test fixes, motivating team actions, and utilizing Railway Oriented Programming. They delve into coding ethics, addressing flaky tests, and supporting junior developers for enhanced productivity.

Sep 5, 2023 • 36min
400: How To Search
Joël and Stephanie discuss the importance of search techniques for developers, sharing tips on efficient searching and the significance of knowing what to Google. They also talk about the challenges faced in integrating with other systems and the benefits of deep reading for software-related topics.

Aug 29, 2023 • 34min
399: Scaling Code Ownership and Accountability
Stephanie's bike camping adventure is discussed, highlighting the joys of biking and camping. The hosts delve into code ownership mechanisms, balancing bureaucracy and collaboration in large teams. They emphasize the social challenges of scaling a team, as much as the technical ones.

Aug 22, 2023 • 34min
398: Developing Heuristics For Writing Software
Want a cool cucumber salad? Joël's got you covered. Stephanie has evolved and found some pickles she enjoys.
Experienced programmers use a lot of heuristics or "rules of thumb" about what makes their code better. These aren't always true, but they work in most situations. Stephanie and Joël discuss a range of heuristics, how to use them, how to come up with them, how to know when to break them, and how to teach them to more junior devs.
Pickled mustard seeds
The purpose of a system is what it does
Intro to empirical software engineering by Hillel Wayne
Transcript:
STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn.
JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way.
STEPHANIE: So, Joël, what's new in your world?
JOËL: So, as of the recording of this, summer is in full swing, and it's the time of year where we have all these, you know, fresh vegetables out, so I've been really enjoying a lot of those. I think this week; in particular, I've been going into, like, all the variations on cucumber salads.
STEPHANIE: Ooh.
JOËL: Yeah. So, that's been kind of fun for me. A fun thing I've been doing to spice this up is pickling mustard seeds to add as a topping. That's actually really amazing. It adds just a little bit of acidity, a little bit of crunch, a little bit of texture. And it's pretty.
STEPHANIE: That sounds so delicious. And also, I was going to share something about pickles about what's new in my world. [laughs] But first, I am curious, what has been your go-to cucumber salad that you put this pickled mustard seed situation on top?
JOËL: So, cucumbers and tomatoes is just the base of everything. And then, it kind of goes with random things I have in my fridge. A little bit of goat cheese on top can be a great topping, big fan of balsamic glaze. You can just get, like, a bottle of that at the grocery store, the pickled mustard seeds. I've recently been trying topping with a fried egg.
STEPHANIE: Ooh, that sounds really fun. It kind of, like, adds a bit of savoriness and creaminess and maybe even, like, the crunchy fried edges. That sounds really yummy.
JOËL: Particularly if you do it over easy where the center is not fully cooked. When the egg breaks, you effectively get salad dressing for free.
STEPHANIE: That sounds so delicious.
JOËL: Summer vegetables, they're great.
STEPHANIE: They are great. Last year, I did have a cucumber garden, as in a garden, and a few cucumber plants that were too prolific for me, to be honest. I found myself overrun with cucumbers and having to give them away because we just didn't eat them enough. And this year, we scaled back a little bit [laughs] on the cucs. But I am so excited to bring up what's new in my world now because it's, like, so related, and we did not plan this at all. But I have a silly little thing to share about my own pickle journey. So, I used to be a pickle hater.
JOËL: You know what? Same.
STEPHANIE: Oh my gosh, incredible. Another new thing we've learned about each other. I really, like, wanted to like pickles because, you know, when you order a sandwich in a restaurant, it always comes with the pickle spear. And neither me nor my partner were into pickles, and we would always leave the spear uneaten on the plate, and we felt so bad about it. I felt really bad about it.
And so, every, like, three to six months or so, I'd be like, okay, I'm going to gather the courage to try the pickle again and see if maybe my taste buds have changed, and this time I'll like it. And, you know, I would try a bite and just be like, no, no, I don't think it's for me. [laughs] But I guess I was just so primed to do something about, like, wanting to eliminate this really inconsequential food waste. But every time it happened, I would just, you know, [laughs] be, like, oh, if only I loved pickles.
And I got my friend, who is a pickle connoisseur, to help me figure out, like, what pickles I might like. So, I asked her to come up with, like, a pickle sampler for me because I really hadn't tried all too many. And that actually really helped me find which ones were a little more palatable to me. So, I found out that I liked the sweeter ones. There's, like, a bread and butter pickle that can be quite sweet. Your diner pickle can be very different from a jar of, like, fancy pickles. [laughs]
JOËL: Definitely.
STEPHANIE: One day, she gifted me a jar of, like, Polish gherkins that were delicious.
JOËL: Hmmm.
STEPHANIE: I was like, wow, I can just snack on these. So, the thing that's new is that this time, I went to an Eastern European grocery store, and I bought my own jar of pickled gherkins. And that was something that Stephanie, like, two years ago, would never even do. [laughs]
JOËL: That's really cool that you got a chance to sort of explore a broader range of what was available in the pickle world and then were able to find kind of your niche there and discover something new that you actually like.
STEPHANIE: Yeah, it was very fun. And now I feel like my whole world has opened up to, you know, pickley and fermented things and just, like, get to enjoy even more snacks.
So, to move away from pickles, recently, on my client project, I've been pairing a lot more with other client developers. And one thing that has come up is, you know, talking about our reasoning or our thought process for when we're pairing on some code. And I realized that I have built up a lot of either intuition or maybe some rules that I like to follow when I'm writing code, writing a test, or even doing a code review. And I've realized that you know, as developers, we often use these kinds of shortcuts or heuristics to help orient us as we're doing our work.
JOËL: Yeah. I think that's definitely something that either comes yourself from experience or sometimes is passed along, and you get to benefit from somebody else's experience. They learned the hard way a lot of these tips and tricks, and now they kind of pass on some of these guidelines to us. Do you have any favorites that you reach for frequently?
STEPHANIE: So, one way I like to approach a problem is to start messy [laughs] and to kind of see what that gets me and then where to go from there. I find that it's a little bit easier for me to draw on things that I've, you know, learned or picked up and tips once I have something in front of me to react to. So, maybe I will just go with the naive implementation and just write all of the code in one method, you know, in a class. And from there, now that it's out of my system, can I kind of come back in with a finer tooth comb and then apply more of a sustained effort to clean things up, right?
And, to me, the question I find myself asking is, like, can this be extracted further? And so, you know, if I have everything in one giant method, then yes, [laughs] there is likely, you know, many opportunities to extract that, and maybe I will see something like, oh, the way that I spaced out this code that might be a signal to me that, like, these are some ideas that are grouped together, and I can pull something out there.
JOËL: Do you have a heuristic around when to stop extracting?
STEPHANIE: That's a good point. I think I tend to stop when I have kind of pulled out the classes that make sense to me. And, at that point, you know, like, maybe there is more extraction that can be done. But at a certain point, you know, you then get these really tiny classes that maybe don't hold their weight. And I think that's also true of methods that then call other methods, and that's the only thing that they do.
Then it's like, well, is this too extracted that it's not really giving a future reader helpful information, right? I want the extraction to improve readability. And that tends to be another lens through which I am applying to this idea of, like, can I extract further? Is this extraction helpful for understanding this code?
JOËL: I like the idea of looking at the code through multiple lenses. And so, sometimes you look at it through the lens of, yeah, are there enough moving parts here? Or does it feel kind of brittle and all in one place? And then sometimes completely shifting your lens and saying, you know what? Let's put myself in the seat of someone who's looking at this code for the first time. Can I understand it?
So, structuring and extracting code is a big part of the work that we do. And I also happen to have a couple of heuristics that I like to use. One is separate branching code from doing code. So, if I have an if...else condition, I try not to put ten lines of logic inside each branch; instead, I have just a call out to a method so that the only thing the conditional does is to choose which path you go, and then each individual path is its own method.
Similarly, if I'm writing a method, I'm not going to have a bunch of logic then a conditional mixed in together. So, my heuristic is a method gets to do one of two things. It either gets to choose a path to take or it gets to do a thing, but you can't mix and match both.
STEPHANIE: Yeah, that makes a lot of sense. I really appreciate a well-named method that is, you know, determining, like, what condition needs to happen because then that helps me, yeah, like, avoid having to hold all of this information about this condition or this other condition, and this other condition in order to figure out what path I'm trying to take.
JOËL: And the naming and the readability, I think, is a big part of this. Another heuristic that I like to use that kind of converges on the same result is trying to write each method at a single level of abstraction. So, if I am writing a method that has some kind of high-level terms it's using, I'm not going to also mix in a lot of low-level implementation. And then, similarly, if it's a method that's doing a lot of, like, low-level nuts and bolts things, I'm going to try not to pull in some of these higher-level domain name methods in there.
And so, by separating things out so that every method reads one level of abstraction, you make it much easier for the reader to go through and figure out what's happening. Are we kind of getting that more 10,000-foot view, getting a sense of what's happening, and saying, okay, we want to process the user form, and then we want to send off an email, and then we want to, you know, write to a file? Or are we going through, okay, we're going to increment a counter so that we get exponential back off on our [inaudible 10:28] request? Those two things do not belong together in the same method.
STEPHANIE: Yeah, absolutely. I really like this heuristic. And I have been applying it more and more and found it really useful for making sure that you're handling your errors correctly, especially because, at different levels of abstraction, you want to do different things with your errors, right?
An implementation error that's raised because, you know, you're calling something accidentally on nil, or maybe a third-party service is down, and you get a custom error, whatever that is, those concerns are different from how you want to handle things at the controller level. And oftentimes, I see those things really mixed together, and honestly, I think leads to a lot of buggy code when you're trying to handle things that can go wrong at the wrong level of abstraction.
JOËL: Yeah. Is there a good heuristic around what level you think is best to trigger an exception? Or maybe, more generally, just being aware of different levels of abstraction and knowing that catching or triggering errors at each level will have different impacts.
STEPHANIE: I think more of the latter, the having an awareness of what kinds of errors might be possible and what impact that has on the user, right? The user being either an actual customer or, you know, another developer who has to read a notification from an error monitoring service. [laughs]
JOËL: This is really interesting to me because I think we've now bridged the concept of heuristics into the idea of mental models. So, the heuristic is write your methods at a single level of abstraction, but that then leads into a mental model where maybe code is structured in three or four different layers. You've got a low level, a mid-level, a high level, something like that, of abstraction. And now, you can use that mental model to start thinking about what are the impacts of exceptions at each layer?
And then, maybe you complete the circle by creating a heuristic that relies on that mental model, maybe, I don't know, raise in the low-level rescue at the top level or something. I'm making something absolutely arbitrary up right now. But somehow, we've gone from heuristic, which creates a mental model, which then allows us to build new heuristics on top of that, and that seems like a virtuous cycle to me.
STEPHANIE: Yeah, absolutely. I think what I'm also picking up is the idea that you do need a mental model, or you do need to draw on your own ideas about something in order to apply the heuristic, right? You know, someone could tell you to separate branching code from doing code. But maybe you don't know what that means or, like, maybe you don't see why that's important. And sure, you can still apply it and try your best to follow it. But, in some ways, I think that the best heuristics are ones that you've kind of developed for yourself based on your own experience.
JOËL: That's really interesting. I think once you've built from your own experience, I definitely feel like they're really impactful because you've kind of synthesized 2, 5, 10, 20 years of experience doing some of this work into, oftentimes, like, you know, a pithy one-line sentence, 5, 6 words that convey an approach that you've found works best, you know, maybe 80% or 90% of the time. The power of synthesis for your own self-learning I think it's really hard to understate.
So, I'm curious if there's any other heuristics that you commonly use that you kind of created yourself based off your own experience rather than just having it be more of a broadly received idea from the community.
STEPHANIE: I think, for me, it's more so that the experience has helped affirm certain heuristics and also made me feel more comfortable with letting others go. And one that I heard a lot but, like, didn't quite understand until really working through it deeper is the idea of feeling pain when you write a test, and that being a signal of opportunities to try different design with your code. And I just didn't know what that pain was at the beginning. Like, what does that even mean? [laughs] Like, how can a test cause me pain?
But on my own, I realized, oh, like, actually, I get really frustrated when I need to stub out a whole method chain, right? And I find myself having to go look up how to do that or just spending a lot of time having to do something that I haven't done before. Maybe the pain comes from having to change a lot of files because, oh no, like, I also broke 20 other tests in the process.
But when you're first starting out, oftentimes, you, like, don't know that that is not normal [laughs]; at least, that was true for me. And so, that was something that I had heard about, like, if you are feeling pain when writing a test, then, like, maybe reconsider your code design. But when you don't know how to identify what that pain is, and you also, like, don't know where to go from there, I find that, you know, the heuristic can only help you so much.
JOËL: Yeah. Maybe that's something that's challenging with a heuristic in that they're often expressed as these pithy sentences. But if you're not familiar with some of the underlying concepts, that might make them harder to apply, which is unfortunate because, oftentimes, these heuristics that we've developed as a community are targeted to newcomers to help them kind of avoid the mistakes that we've made along the way.
STEPHANIE: I think what really helped me the most in connecting a heuristic that's commonly expressed and my own experience is when I've had someone ask me about how I'm feeling when I'm, you know, making some kind of decision or when I'm reading some code. Like, what do I think of this, or what has been my experience with this? And giving me the opportunity on the spot to synthesize that information. Because otherwise, it's hard to figure out, you know, like, what is just normal? This is just life as a developer [laughs]. And what are opportunities to maybe gain some more insight about the work itself?
JOËL: One thing that I've learned over time as a developer, and I'm not sure if this quite rises to the level of a heuristic, but a lot of, like, pain and frustration in development doesn't necessarily have to be that way. And it's not necessarily because I'm bad at the job or I'm too new to the technology or whatever. It can often be a sign of underlying design issues or the fact that the system was modeled with certain assumptions that are no longer true. These can often be signals that you can make things better.
So, I think if I had to reduce this idea down to a clever one-liner, it'd be something along the lines of, it can be better, or it doesn't have to be this bad. You're writing a test, and it's really annoying. There might be a better way to structure the underlying code that would make the test better. You're having to do some, like, really clunky code to deal with something. Is there maybe a better object design that would make a lot of that pain go away, or at least kind of quarantine it in a certain part of the codebase?
STEPHANIE: I actually think you're really onto something because what I was just hearing, I love that, like, it can be better. It's less prescribed, I guess, than some other heuristics, like, you know, do not repeat yourself, or whatever.
JOËL: Classic.
STEPHANIE: [laughs] It really encourages, like, the individual to think a little deeper. And it actually reminded me of another...this is actually a bit of a pithy saying, but I find it to be really useful. And I'm curious if you've heard it before. It's a systems thinking heuristic, and the phrase is, the purpose of a system is what it does.
JOËL: Ooh, I have heard that, and I'm trying to remember what context.
STEPHANIE: So, it was coined by a systems thinking expert. Stafford Beer, I think, is his name. And I recently learned about it from a friend. But I think the cool thing is that it can be applied to literally anything [laughs] because everything is a system, you know, or not just software. But I have found a lot of value in applying it to just, like, is this function doing what it says it does, right? Or is it actually also doing, like, a side effect? And turns out, maybe we want to bring that into alignment with what the name of the function is, or try pulling that out, or whatever. I think it can also be true of test suites.
I don't know if this is a heuristic or not. But the idea that we should always be testing or all tests are good, yeah, I guess that could pass as a heuristic. By bringing this perspective of the purpose of a system is what it does, it's like, well, is the test suite also so bloated and takes so long and so flaky that it is actually hindering development? And if that is the case, then maybe there is some reevaluation necessary, right? Rather than just claiming that it's helping us have more confidence in our code when that may or may not be true.
JOËL: You brought up an interesting idea here, which is that heuristics aren't always right. So, you're talking about the idea that a heuristic like good code is tested code might not be correct in 100% of the cases. Like, how accurate does a heuristic need to be in order for it to be really valuable? You know, you're hoping for something that's, like, 90% correct that you can follow most of the time, except in some edge cases, or something maybe as low as, like, 50% where it's a coin toss whether the heuristic applies in the situation or not. Are those still useful? Or are they maybe more confusing than otherwise?
STEPHANIE: Oh wow. That's a really interesting way to frame it because I don't know if I've ever stored information about how well my heuristics are serving me. [laughs] But I do really like the idea that you can use a heuristic as a guiding principle just to try and that you can always back out of it, right?
So, if you're wanting to take DRY to the extremist of extremes, just for fun or just to see how that might go, you can go down that path and, at any point, decide, okay, like, I like this, or I don't like this, and choose a different path. But the idea of kind of tracking, like, how well they're working for you that is really interesting to me, and not something I've tried before.
JOËL: I love the idea of taking a heuristic and, like, doing a side project whose whole goal is just to kind of push that heuristic to the extreme, to the breaking point so that, that way, you get an intuition of, like, when does it work for you? When does it not? That sounds like a really fun exercise for someone to do. Is that something that you've done yourself?
STEPHANIE: Not to the point of a whole side project, but just like I like to try pickles randomly every now and then to see if I like them, [laughs] will just try a new technique and see how it goes. In an episode a while back, we talked about whether we TDD or not, and, to be honest, I don't do it, you know, 100% of the time or all the time. But one day, I did decide to TDD a full-stack feature from start to finish just for fun [laughs], and I enjoyed it. I learned some things about it.
And I think now I've kind of integrated the parts that I liked about it into my development flow. Like, I'm not always going to do it. But I think it also just helped me figure out, like, okay, like, what is this thing about that people claim that is the pinnacle of how we should be writing our code? And how can I decide for myself, like, whether it works for me or just pick and choose the parts of it that work for me?
JOËL: Yeah. That just seems like a really valuable exercise. There are definitely too many heuristics out there to do that for everything. But I guess I've never thought of it quite so concretely. But I almost wonder if I should, like, add this to my kind of personal growth plan to say, like, once a year, I'm going to take a heuristic and kind of push it to an extreme and see what I can learn about it.
STEPHANIE: I actually think what's really cool is the process of, like, any individual developer figuring out what kinds of heuristics they want to follow, as opposed to, you know, like, a mass proclamation that, like, this is the way, right? Are there any heuristics that you have maybe picked up and then let go of because you realized that, you know, they weren't working enough or frequently enough for you or that you just didn't like?
JOËL: I don't know about, like, fully letting go, but definitely kind of recontextualize and sometimes even sort of rewrote them a little bit to work for me. So, a classic one would be the idea that shorter code is more readable. So, it's common to see comments on a pull request sort of like, "Hey, you could make this shorter by doing this." And that can be true to a certain extent. When you get to the point where you're playing code golf, it becomes absolutely unreadable.
But also, there's a point where sometimes using some other heuristics will result in longer code but actually make it more readable on the whole. And so, packing everything into one method might be overall shorter, so it's fewer lines to read going through a class. But maybe extracting some methods or doing that separating branching code from doing code might lead to an overall longer class but an also overall more readable one. So, I think there's probably a lot of caveats that go with that idea. Oftentimes, shorter can be more readable with, you know, two or three asterisks that maybe go a little bit more into the why that is the case.
STEPHANIE: Yeah. I like the contextualizing. That actually reminded me of a talk that I watched recently by Hillel Wayne. It's called Intro to Empirical Software Engineering. And he basically, like, does a deep dive into all these studies about software practices that we think are, quote, unquote, "good," like, as a community or as an industry. And it's like, well, like, how do we actually know? Like, show me the research, right?
And one of the studies that he included was trying to determine if using abbreviations for variable names or using the full words made the code easier to debug or not. And so, the main example that he was using was employee number as a variable, and the abbreviation was EMP num. And it turns out that there was no difference in how easy it was to debug. But the approach that each group that was studied differed.
So, the folks who had the full names, the full words for the variable names, were kind of using an approach of just scanning the code and being able to understand at a higher level the domain, right? Whereas the folks who were debugging with just abbreviations had to work at a bit of a lower level and, you know, or maybe using breakpoints and debugging the code that way.
And I thought that was really cool because, first of all, I think it kind of was trying to prove that, like, we don't actually know if one is better or not. But what is important and interesting to me is the idea that, like, you can choose the method that you like better or that works for you and the human side of it, right? The impact it has on our process.
JOËL: That's really cool. I'll have to go and watch that talk. Building this kind of context and nuance around a heuristic, though, takes a lot of time, takes experience. And part of the value of a heuristic is that we're collapsing down maybe our own experience or somebody else's experience into something that doesn't require you to necessarily do all that work upfront.
How do you feel about sharing and kind of targeting a lot of these heuristics to newer coders who are kind of trying to get better at their craft and looking for ways to improve without necessarily having to do, you know, five years of experience digging into a particular topic? Do you think heuristics are helpful, or do they maybe mislead?
STEPHANIE: I really value when they're presented as an opinion, as opposed to a true fact about code. [laughs] Because I really appreciate when someone is able to explain to me why they chose readability in this particular scenario or why they chose speed and performance. Or maybe they were making a trade-off between accessibility and, you know, something else. To just, like, tell someone, "Oh yeah, like, DRY code is better code," or to just tell someone that without the explanation with, like, offering them the opportunity to reflect themselves on, like, oh, like, where have I seen DRY code that was easier for me to read? That seems a little less helpful in terms of investing in their growth.
JOËL: Yeah. Definitely, I think sharing some of the purpose behind it can often be really useful because most of these heuristics are never an end unto themselves. They're a means to some other end. So, you're not writing code that's DRY just because you want to be cool. You're writing code to be DRY because you're trying to improve readability, make it easier to change so you don't have to change it in multiple places. You want to maybe reduce the chance of certain types of bugs.
These are all actual purposes of what you want to do in your code. DRY is just one way of getting there. But oftentimes, we might skip that part and just be like, hey, you should make your code DRY because DRY is the best. And it can be, but it's in service to these other goals.
STEPHANIE: I think when I am sharing those types of heuristics that are more commonly held, I also do like to preface, like, some people think this, or some people like to do things this way, just to be clear that they don't have to like it or do it. In general, I always prefer injecting more nuance [laughs] into the conversation. But yeah, like, it is a really personal process, I think, and figuring out, like, how any individual makes decisions about, like, all the code they're writing. You have to make a million [laughs] decisions every time you do it.
So, yes, like, those heuristics do provide a shortcut. And also, I think it's worth taking the time to think about if it's working, especially for the specific context that you're applying it, right? Because that also can change. And, I don't know, maybe I'm just skeptical of any one size fits all solution.
JOËL: I think for myself, with many heuristics, as a beginner coder, I had a bit of, like, a spiral journey, or maybe kind of going up a set of stairs. So, as a brand-new developer, I would make a lot of duplication bugs in my code, where, you know, I would have the same value in multiple places, and then I'd change it in one place, and I don't remember to change it in other places, and the code breaks.
And so, being introduced to the idea of DRY actually helped my code get quite a bit better. It was, like, a net positive on my experience because I was not getting burned by all these bugs quite so frequently. And so, for a while, just throwing more DRY into my code just made my life better. And then, eventually, you kind of hit that plateau where I don't run into the pain of these bugs anymore. But now I keep doing more DRY somewhat mindlessly. And I end up with this pile of abstractions that are actually really brittle or frustrating to work with. And now, I have to rethink some of the assumptions behind the heuristic.
And then, at that point, yep, maybe recontextualize a little bit, learn about when it's good, when are the trade-offs not worth it. Now I have a better understanding, and I kind of go on another growth bit where it makes a lot of my code better until maybe I hit another plateau. I've kind of maxed out the benefits. I start seeing some of the pain, and then, again, I have to go through this cycle again. And maybe the approach you were talking about earlier, where you do a side project and kind of push a heuristic to its breaking point, is a way to kind of speed run that process.
STEPHANIE: Yeah, that's really interesting because you're just committing to it and trying to learn everything you can from it in a very concentrated setting. I also wonder, and it's totally fine if you don't know, but if someone had told you kind of all of those reasons you listed about why DRY code, like, what that achieves, if that may have reframed how you were thinking about applying it. Or was that also something that had to come from doing it enough?
JOËL: I think as a brand-new developer, a lot of that would have gone over my head. I was still really shaky on the concept of abstraction. When is it useful? When is it not? So, a lot of those more subtle pitfalls, I think, would not have been relevant to me at that point in my career, even the concept of readability, right? When I'm a brand-new programmer, I'm still getting used to reading a lot of code.
And so, the idea that code might be written in a way that's unreadable or more challenging to read, it might just feel like, oh, I just need to get better, improve myself. It's not that the code is written in a hard-to-read way. It's just I don't have enough experience at reading code. And I think that's a common thing that we do as beginners at everything, right? We start by blaming ourselves when things get hard.
STEPHANIE: Yeah. I was just thinking that, you know, if you are sharing heuristics with a newer developer or an early-career developer, at the end of the day, like, really, I'm not sure about the value of just dropping it on them and letting them run [laughs] with it. But I think what could be really, really effective is just having a sustained relationship with them and, like, continuing that conversation. It's, like, maybe in a code review or in a pairing session being like, "Oh yeah, like, I see you're practicing DRY. Like, what do you think about how this made this piece of code different?" And kind of baking in that process of self-discovery along the way and speeding it up in that way as well.
JOËL: So, what you're really saying is the one heuristic to rule them all is code in community.
STEPHANIE: I love that. I'm totally with you.
JOËL: On that note, shall we wrap up?
STEPHANIE: Let's wrap up.
Show notes for this episode can be found at bikeshed.fm.
JOËL: This show has been produced and edited by Mandy Moore.
STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show.
JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter.
STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email.
JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week.
ALL: Byeeeeeee!!!!!!
ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.Support The Bike Shed

4 snips
Aug 15, 2023 • 43min
397: Dependency Graphs
Stephanie is consciously trying to make meetings better for herself by limiting distractions. A few episodes ago, Joël talked about a frustrating bug he was chasing down and couldn't get closure on, so he had to move on. This week, that bug popped up again and he chased it down! AND he got to use binary search to find its source–which was pretty cool!
Together, Stephanie and Joël discuss dependency graphs as a mental model, and while they apply to code, they also help when it comes to planning tasks and systems. They talk about coupling, cycles, re-structuring, and visualizations.
Ruby Graph Library
Graphviz
Using a Dependency Graph to Visualize RSpec let
Mermaid.js
Strangler Fig pattern
Transcript:
JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville.
STEPHANIE: And I'm Stephanie Minn. And together, we're here to share a bit of what we've learned along the way.
JOËL: So, Stephanie, what's new in your world?
STEPHANIE: So, I'm always trying to make meetings better for me [chuckles], more tolerable or more enjoyable. And in meetings a lot, I find myself getting distracted when I don't necessarily want to be. You know, oftentimes, I really do want to try to pay attention to just what I'm doing in that meeting in the moment. In fact, just now, I was thinking about the little tidbit I had shared on a previous episode about priorities, where really, you know, you can only have one priority [laughs] at a time. And so, in that moment, hopefully, my priority is the meeting that I'm in.
But, you know, I find myself, like, accidentally opening Slack or, like, oh, was I running the test suite just a few minutes before the meeting started? Let me just go check on that really quick. And, oh no, there's a failure, oh God, that red is really, you know, drawing my eye. And, like, could I just debug it really quick and get that satisfying green so then I can pay attention to the meeting? And so on and so forth. I'm sure I'm not alone in this [laughs]. And I end up not giving the meeting my full attention, even though I want to be, even though I should be.
So, one thing that I started doing about a year ago is origami. [laughs] And that ended up being a thing that I would do with my hands during meetings so that I wasn't using my mouse, using my keyboard, and just, like, looking at other stuff in the remote meeting world that I live in. So, I started with paper stars, made many, many paper stars, [laughs] and then, I graduated to paper cranes. [laughs] And so, that's been my origami craft of choice lately.
Then now, I have little cranes everywhere around the house. I've kind of created a little paper crane army. [laughs] And my partner has enjoyed putting them in random places around the house for me [laughs] to find. So, maybe I'll open a cabinet, and suddenly, [laughs] a paper crane is just there. And I think I realized that I've actually gotten quite good at doing these crafts.
And it's been interesting to kind of be putting in the hours of doing this craft but also not be investing time, like, outside of meetings. And I'm finding that I'm getting better at this thing, so that seemed pretty cool. And it is mindless enough that I'm mentally just paying attention but, yeah, like, building that muscle memory to perfecting the craft of origami.
JOËL: I'm curious, for your army of paper cranes, is there a standard size that you make, or do you have, like, a variety of sizes?
STEPHANIE: I have this huge stack of, like, 500 sheets of origami paper that are all the same size. So, they're all about, let's say, two or three inches large. But I think the tiny ones I've seen, really small paper cranes, maybe that would be, like, the next level to tackle because working with smaller paper seems, you know, even more challenging.
JOËL: I'd imagine the ratio of, like, paper thickness to the size of the thing that you're making is different.
STEPHANIE: At this point, they say that if you make 1,000, then you bring good luck. I think I'm well on my way [laughs] to hopefully being blessed with good luck in this household of my little paper crane army.
JOËL: It's interesting that you mentioned the power of having something tactile to do with your hands during a meeting, and I definitely relate to that. I feel like it's so easy, even, like, mindlessly, to just hit Command-Tab when I'm doing things on a screen. Like, my hands are on the keyboard. If I'm not doing something, I'm just going to mindlessly hit Command-Tab. It's kind of like on your phone sometimes. I don't know if you do this, like, just scrolling side to side. You're not actually doing anything. You just want motion with your fingers.
STEPHANIE: Yes. I know exactly what you're talking about. And it's funny because it's a bit of a duality where, you know, when you are in your development workflow, you want things to be as quick and convenient as possible, so that Command-Tab, you know, is very easy. It's just built in, and that helps speed up your, you know, day-to-day work. But then it's also that little bit of mindlessness, I think, that can get you down the distraction path.
When I was first looking for something to do with my hands, to have, like, a little tactile thing to keep me focused in meetings, I did explore getting one of those fidget cubes; I have to say. [laughs] It's just a little toy, you know, that comes with a bunch of different settings for you to fidget with.
There's, like, a ball you can roll, you know, with your thumb, or maybe some buttons to click, and it gives you that really satisfying tactile experience. And I know they work really well for a lot of people, but I've really enjoyed the, I guess, the unexpected benefits [chuckles] of getting better at a hobby [laughs] while spending my time at my work.
Joël, what is new with you?
JOËL: So, a few episodes ago, I talked about a really kind of frustrating bug that I was chasing down that was due to some, like, non-determinism in the environment. And it kind of came, and then it went away. And I wasn't able to get sort of closure on that and had to move on. Well, this week, that bug popped up again, and this time, I was actually able to chase it down. So, that felt really exciting. And I got to use binary search to try to find the source of it, which made me feel really cool.
STEPHANIE: Oooh, do tell. What ended up being the issue?
JOËL: I'm connecting to an external Snowflake data warehouse, and ActiveRecord tries to fetch the schema and crashes as part of that with some cryptic error that originates from the C extension ODBC Ruby driver package. I figured out that it's probably something to do with, like, a particular table name or something in the table metadata when we're pulling this schema that we're not happy about. But I don't know which table is the one that it's not happy with.
Well, this time, I was able to figure out, by reading through some of the documentation, that I can pull subsets of the schema. So, I can pull the first n values of that schema, and it won't crash. It only crashes if I try to fetch the entire set, which is what is happening under the hood. At that point, you know, I could fetch each row individually, but there's hundreds of these. So, you know, I try, okay, what happens if I try to fetch 1,000 of these? Is it going to crash? Because it's a massive system. So, yes, I get a crash.
So, I know that a table less than a thousandth in the list of tables is what's causing the problems. So, okay, fetch 500 halfway in between there. It's still going to crash. Okay, 250, 125. I then kind of keep halving all the time until I find one that doesn't crash. And now I know that it is somewhere between the last crash and this one. So, I think it was between 125 and 250. And now I can say, okay, well, let's fetch the first, you know, maybe 200 tables, okay, that crashes. And I keep halving that space until you finally find it. And then, like, okay, so it's this one right here.
Now, the problem is the bad table actually crashes. So, I think it ended up being, like, number 175 or something like that. So, I never get to see the actual table itself. But because the list of tables is in alphabetical order, and I can see because I can fetch the first 174 and it succeeds, so I can tell what the previous 5, 6, you know, previous 174 are.
I can pretty easily go and look at the actual database and the list of tables and say, okay, well, it's in the same order. And the next one is this one, and hey, look, there is some metadata there that has some very long fields that are longer than one might expect, specifically going over a potentially implied 256-character limit. That seems somewhat suspicious. And, oh, if we remove this table, all of a sudden, everything works.
STEPHANIE: Wow, binary search, an excellent debugging tool [laughs] when you have no idea, you know, what could possibly be causing your issue.
JOËL: It's such a cool tool. Like, I'm always so happy when I get a chance to use it. The problem is, you need a way to be able to answer the question, like, have I found it? Yes or no? Or, generally, is it greater or less than this current position?
STEPHANIE: Well, that's really exciting that you ended up figuring out how to solve the bug. I know last time we talked about it, you kind of had left off in a space of, hopefully, we won't run into this issue again because it's no longer happening. But it seems like you were also set up this time around to be able to debug once it cropped up again.
JOËL: Yes. So, binary search is really cool. It's got this, like, very, like, fancy computer science name. But in reality, it's a fairly simple, straightforward technique that I use fairly frequently in my development. And there's another kind of computer sciency fancy-sounding concept that I use all the time. You've all heard me reference this multiple times on the show. You're right; we're finally doing it. This is the dependency graph episode.
STEPHANIE: Woo. [laughter] It's time. I'm excited to really dig into it because, you know, as someone who has heard you talk about it a lot, you know, and is maybe a little less familiar with graph theory and how, you know, it can be applied to my day to day work, I'm really excited to dig into a little bit about, you know, what a regular developer needs to know about dependency graphs to add to their toolbox of skills.
JOËL: So, I think at its core, the idea of a dependency graph is that you have a group of entities, some of which depend on each other. They can't do a task, or they can't be created unless some other subtasks or dependent actions take place. And so, we have a sort of formal structural way of describing these things. Visually, we often draw these things out where each of the pieces is like a little bubble or a circle, and then we draw arrows towards the things that it depends on.
So, if A cannot be done without B being done first, we draw an arrow from A to B. That's kind of how it is in the abstract. More concretely, this kind of thing shows up constantly throughout the work that we do because a lot of what we do as developers is managing things that are connected to each other or that depend on each other. We build complex systems out of smaller components that all rely on each other.
STEPHANIE: Yeah, I think it's interesting because I use the word dependency, you know, very frequently when talking about normal work that I'm doing, you know, dependencies as in libraries, right? That we've pulled into our application, or dependencies, like, talking about other classes that are referenced in this class that I'm working in. And I never really thought about what could be explored further or, like, what could be learned from really digging into those connections.
JOËL: It's a really powerful mental model. And, like you said, dependencies exist all over our work, and we often use that word. So, you mentioned something like packages, where your application depends on Rails, which in turn depends on ActiveRecord, which in turn depends on a bunch of other things. And so, you've got this whole chain of maybe immediate dependencies, and then those dependencies have dependencies, and those dependencies have dependencies, and it kind of, like, grows outward from there.
And in a very kind of simplistic model, you might think, oh, well, it's more, like, a kind of a tree structure. But oftentimes, you'll have things like branches on one side that connect back to branches on the other. And now you've got something that's no longer really tree-like. It's more of a sort of interconnected web, and that is a graph.
STEPHANIE: I think understanding the dependencies of your system has also become more important to me as I learn about things that can go wrong when I don't know enough about what my system is, you know, relying on that I had kind of taken for granted previously. I'm especially thinking about packages like we were mentioning, and, you know, not realizing that your application is dependent on this other library, right? That's brought in by a gem that you're using. And there's maybe, like, a security issue, right? With that.
And suddenly, you have this problem on your hands that you didn't realize before. And I know that that has been more of a common discussion now in terms of security practices, just being more aware of all the things that you are depending on as really our work becomes more and more interconnected with the things available to us with open source.
JOËL: I think where understanding the graph-like nature of this becomes really important is when you're doing something like an upgrade. So, let's say you do have a gem that has a security problem, and you want to upgrade it to fix that security issue. But the upgrade that includes the security patch is also a breaking upgrade. And so, now everything else in your system that depends on that gem or on that package is going to break unless you have them in a version that is compatible with the new version of that gem.
And so, you might have to then go downstream and upgrade those packages in a way that's compatible with your app before you can bring in the security patch. And a lot of that can be done automatically by Bundler. Bundler is software that is built around navigating dependency graphs like that and finding versions that are compatible with each other.
But sometimes, your code will need to change in order to upgrade one of these downstream gems so that you can then pull in the upgrade from the gem that needs a security patch. And so, understanding a little bit of that graph is going to be important to safely upgrading that gem.
STEPHANIE: So, I know another application of dependency graphs that you have thought about and written a blog post for is RSpec let declarations and how a lot of the time when we are using let, you know, we are likely calling other variables defined by let. And so, when you are encountering a test file, it can be really hard to grok what data is being set up in your test.
JOËL: Yeah, so that is really interesting because you can define something that will get executed in a lazy fashion if it gets referenced. But then not only is the let lazy and will not trigger unless it's referenced, but a let can reference other lets, which are also lazy, and only get triggered if they get referenced.
So, you might have a bunch of lets defined in any order you want throughout a file, and they're all kind of interconnected with these references to each other. But they only get triggered if something calls it directly or it's in this, like, chain of dependencies. And getting a grasp on what actually gets created, which lets will actually execute, which ones don't in a file can quickly get out of hand. And so, thinking of this in terms of a dependency graph has been a really helpful mental model for me to understand what's going on in a complex test file.
STEPHANIE: Yeah, absolutely. Especially when sometimes the lets are coming from all over the place, you know, maybe a describe block hundreds of lines away, or even a completely different file if you are using a shared context that's being pulled in. So, I can see why this was a complex problem that could be made a little simpler with plotting out a dependency graph.
And in preparation for this episode, I was doing a little bit of my own exploration on this because I certainly know, you know, the pain of trying to figure out what is being executed in my tests when there are a lot of lets that reference each other. And in the blog post, you kind of gave a little step-by-step of how you could start with creating a dependency graph for the test that you're working with.
And I was really curious if this process could be automated because, you know, I do enjoy, you know, pulling out the pen and paper [chuckles] every now and then. But I'm not, like, a particularly visual person. God forbid I, like, draw a circle, but then, like, don't have enough space for the rest of the circles. [laughs] So, I was really hoping for a tool that could do this for me, especially if, you know, you do, you have a lot of tests that you have to try to understand in a relatively short amount of time. And so, I ended up doing something kind of hacky with RSpec and overriding let definitions to automate this process.
JOËL: That's really cool. So, is the tool that you're trying to build something where you feed it in a spec file, and it gives you some kind of graphical representation like an SVG or something as output?
STEPHANIE: Yeah. I did consider that approach first, where you feed in the file, but then I ended up going with something more dynamic where you are running the test, and then as it gets executed, tracing the let definitions and then registering them to build your dependency graph.
JOËL: So, you've got some sort of internal modeling that describes a dependency graph. And then, somehow, you're going to turn that, you know, a series of Ruby objects into some kind of visual.
STEPHANIE: Yeah, exactly. And the bulk of that work was actually done with a library called RGL, which stands for just Ruby Graph Library. [laughs] And what's nice is that it has a really easy interface for plugging in the vertices and edges of the dependency graph that you want to build. And then, it is already hooked up with Graphviz to, you know, write the SVG to a file. And so, I ended up really just having to build up an array of my dependencies and the connections to each other and then feed it into the constructor of the graph.
JOËL: And for all of our listeners, you mentioned Graphviz. That is a third-party tool that can be installed on your machine that can generate these SVG diagrams from...I believe it has its own sort of syntax. So, you create, I believe it's dot, D-O-T, so dot dot file. And based off of that, it generates all sorts of things, but SVG being potentially one of them.
STEPHANIE: Yeah. The nice thing was that I actually didn't end up having to use the DSL of Graphviz because the RGL gem was doing them for me.
JOËL: Nice. So, it plugs in directly.
STEPHANIE: Yeah, exactly. And I was really curious about using this gem because I, you know, just wanted to write Ruby, especially to plug into other things that are already in Ruby. And I found that surprisingly easy, thanks to all of the RSpec config options that they make available to you, including an option to extend the example group class, which is actually where let and let bang is defined.
And so, I ended up overriding those classes and using, you know, the name of the let that you're defining and then the block to basically register the dependencies. And I also ended up exploring a little bit with using Ruby's built-in parser to figure out in the block that's being passed to the let, what parts of that block could potentially be a reference to another let.
JOËL: That's really cool. Did you get any fun results from that?
STEPHANIE: I did. It worked pretty well in being able to capture all of the let declarations, and other lets that it references. And so, I was able to successfully, you know, like, generate a visual dependency graph of all of the lets, so that was really neat.
The part that I was really kind of excited about trying next, though I didn't end up having time to yet, was figuring out which of those let values are executed by way of the let bang, right? Which is eager or what is referenced in the test that then gets executed as well. And so, the RGL library is pretty neat and has some formatting options, too, with the Graphviz output. So, you can change the font color or styling options for different, you know, nodes and edges. And so, I was really curious to pursue this further, maybe, and use it to show exactly what gets evaluated now that I have successfully mapped my let graph.
JOËL: Right. Because the whole point of this exercise is that not the entire graph is going to get evaluated. The underlying question is, what data actually gets created when my test runs? And so, you build out this whole dependency graph, and then you can follow a few simple rules to say, okay, this branch gets called, this branch gets called, this series of things gets called. And okay, this subset of let blocks trigger, and therefore this data has been created for my given test.
STEPHANIE: Yeah. Though I will say that even where I got so far to, just seeing all of the let definitions in a spec file was really helpful to have a better understanding, you know, if I do have to add a test in here, and I'm thinking about reaching for a pre-existing let declaration, to be like, oh, like, it actually, you know, goes on to reference all of these other things that may be factories [chuckles] that are created might make me, you know, think twice, or just have a little better understanding of what I'm really dealing with.
JOËL: Right. The idea that when you're calling out to a let, or a factory, or something else that's just a node in a large graph, you're not necessarily referencing just one thing. You might actually be referencing the head of a very long chain of things that maybe you don't intend to trigger the whole thing.
STEPHANIE: Yeah, exactly.
JOËL: So, in that sense, having a sort of visual or at least an idea of the graph can give you a much better sense of the cost of certain operations that you might have to do.
STEPHANIE: The cost of the operations certainly, especially when, you know, you are working in a legacy codebase, and you, you know, like, maybe don't know how everything plays together or is connected. And it's very tempting to just reach for [chuckles] the things that have been, you know, created or built for you. And I'm certainly guilty of that sometimes on this client project, where the domain is so complex, and there are so many associated models.
And I'm like, well, like, let me just, you know, use this let that already, you know, has a factory set up for what I think I need for this test. But then realizing, oh, actually, like, it is creating all these things, and do I really need them? I think it can be really challenging to unravel all of that in your head. And so, with this very scrappy tool that I [chuckles] built for my own purposes, you know, maybe it makes it, like, one step easier to try to fully understand what I'm working with and maybe do something different.
JOËL: One aspect that I think is really powerful about dependency graphs is that it takes this kind of, like, abstract concept that we oftentimes have an intuitive sense around, the idea that we have different components that depend on each other, and it shows it to us visually on, like, a 2D plane. And that can be really helpful to get an understanding or an overview of a system.
You mentioned that RGL uses Graphviz to generate some SVGs. A visual tool that I've been using to draw some of my dependency graphs has been mermaid.js. It has a syntax that's, like, a text-based syntax, but it's almost visual in that you have a piece of text and name of a node. And then, you'll draw a little ASCII arrow, you know, two dashes and a greater than sign to say this thing depends on, and then write another name, and just have a row, like, a bunch of entries to say; A depends on B. A also depends on C. C depends on D, and so on, and, like, build up that list. And then Mermaid will just generate that diagram for you.
STEPHANIE: Yeah. I've used Mermaid a few times. One really helpful use that I had for it was diagramming out a bunch of React components that I had and wanting to understand the connections between them. And I think you can even paste the Mermaid syntax into your GitHub pull request description, and it'll render as the graph image.
JOËL: Yeah, that's what's really cool is that Mermaid syntax has become embedded in a lot of other places in the past few years. So, it's really easy to embed graphs now into all sorts of things. You mentioned GitHub. It works in pull requests descriptions, comments, I think pretty much anywhere that Markdown is accepted. So, you could put one in your README if you wanted.
Another place that I use a lot, Obsidian, my note-taking tool, allows me to embed graphs directly in there, which is really much nicer than previously; sometimes, when I wanted to express something as a visual, I would use some sort of drawing tool to do something and export an image, and then embed that in my note. But now I can just put in this text, and it will automatically render that as a diagram.
And part of what's really nice about that is that then it's really easy for me to go and change that if I'm like, oh, but actually, I want to add one more connection in here. I don't have to re go back to, hopefully, a file that I've saved somewhere and, like, change an image file and re-export it. I just, you know, I add one line of text to my note, and it just works.
STEPHANIE: That's awesome. Yeah, the ability to change it seems really useful.
So, we've talked a little bit about tools for creating a visual aid for understanding our dependencies. And now that we have our graph, maybe we might have some concerning observations about what we see, especially when perhaps some of our dependencies are pointing back to each other.
JOËL: Yes. So, I think you're referencing cycles, in particular. That would be the formal term for it. And those are really interesting. They happen in dependency graphs. And I would say, in many cases, they can be a bit of a smell. There's definitely situations where they're fine. But there are things that you look at, and you're like, okay, this is going to be a more complex kind of tricky bit of the graph to work with.
Some cases, you just straight up can't have them. So, I want to say that the way RSpec lets are set up, you cannot write code that produces cycles. But you might have...I think Ruby allows classes to reference each other in such a way that it creates a cycle, and not all languages do that. So, Elm and F#, I believe, require that modules cannot reference each other. The fancy term for this is a dependent acyclic graph, or DAG, which basically just means that there are no cycles in that graph.
STEPHANIE: Yeah. What you said about classes referencing each other is very interesting because I've definitely seen that. And then, if I have to go about changing something, maybe even it's just the class name, right? Now there's no way in which I can really make just one change. I have to kind of do it all in one go.
JOËL: I think that's a common property of a cycle, and a graph is that changes that happen somewhere in that cycle often need to be all shipped together as one piece. You can't break it up into smaller chunks because everything depends on everything else. So, it has to be kind of boxed together and shipped as one thing.
STEPHANIE: And you'd mentioned that cycles, you know, can be a bit of a code smell. And if the goal is to be able to break it up so that it is a little bit more manageable to work with, how would you go about breaking a cycle?
JOËL: So, I think breaking a cycle is going to vary a little bit based on your problem domain. So, are you modeling a series of classes that are referencing each other? Is this a function call graph? Is this even, like, a series of tasks that you're trying to do? But typically, what you want to do is make sure that eventually, at some point, like, something doesn't loop back to referencing something higher up in your hierarchy. And so, oftentimes, it ends up being about what is allowed to know about what? Do you have higher-level concepts that can know and depend on lower-level concepts but not vice versa?
And again, we are talking about this a little bit at the abstract level. But in terms of, let's say, different code modules, or classes, or something like that, commonly, you might say, well, we want some sort of layering where we have almost, like, more primitive types of classes at the bottom. And they don't get to know about anything above them. But the ones above that might be more complex that are composed of smaller pieces know about the ones below them. And you might have multiple layers kind of like that that all kind of point down, but nothing points up.
STEPHANIE: That is a very common heuristic. [chuckles] I think you were basically just describing how I also understand creating React components, where you want to separate your presentational ones from your functional ones. And, yeah, it makes a lot of sense that as soon as you start adding that complexity of, you know, those primitive classes at the bottom, starting to, you know, point to things higher up or to know about things higher up, that is where a cycle may be accidentally introduced.
JOËL: It's interesting just how many design principles that we have in software. If you dig into them a little bit, you find out that they're about decoupling things, and oftentimes, it's specifically breaking up cycles. So, one way that you might have something like this that actually has dependency in the name, the dependency inversion principle, where what you're effectively doing is you're taking one of those dependency arrows, and you're flipping it the other way. So, instead of A depending on B, you're flipping it. Now B depends on A, and that can be enough to break a cycle.
STEPHANIE: So, one thing I've picked up from our conversations about dependency graphs is that oftentimes, you know, when you're trying to figure out where to start, you want to look for those areas or those nodes where there's nothing else that depends on it.
JOËL: Yeah. I think you have those nodes that, if this were a tree, you would call them the leaf nodes. In the case of a graph, I'm not sure if that's technically correct, but they don't depend on anything. They're kind of your base case. And so, you can, you know, if it's a function, you can run it. If it's a file, you can load it; if it's a class, also you can load it up and not have to do anything else because it has no dependencies. And knowing that those are there, I think, can be really useful in terms of knowing an order you might want to execute something in. And this is really interesting for one of my favorite uses of a graph, which is breaking down a series of tasks that you need to do.
So, commonly, you might say, okay, I have a large task I need to do. I break it down into a series of subtasks. And, you know, maybe I draw out, like, a bulleted list and, you know, task 1, 2, 3, 4, 5. The problem is that they're not necessarily just a flat list. They all have, like, orders, like dependencies between each other. So, maybe one has to happen before 2, but it also has to happen before 3, which needs to happen before two, and, like, there's all these interconnections.
And then, you find out that you can't ship them independently the way you thought initially. So, by building up a graph, you end up with something that shows you exactly what depends on what. And then, like you said, the parts that are really interesting where you can start doing work are the ones that have no dependencies themselves. Other things might depend on them, but they have no dependencies. Therefore, they can be safely built, shipped, deployed to production, and they can be done independently of the other subtasks.
STEPHANIE: Yeah. I was also thinking about things that could be done in parallel as well. So, if you do have multiple of those items with no dependencies, like, that is a really good way to be able to break up that work and, yeah, identify things that are not blocked.
JOËL: For a complex set of tasks, it's great to see, okay, these two pieces have no dependencies. We can have them be done in parallel, shipped independently. And then you can just kind of keep repeating that process. Because once all of the tasks that have no dependencies have been done, well, you can almost, like, remove them from the graph and see, okay, what's the new set of things that have no dependencies? And then, keep doing that until you've eventually done the whole graph.
And that may sound like, oh okay, we're just kind of using a little bit of intuition and working through the graph. It turns out that this is a, like, actual, like, formal thing. When it comes to graphs, it's a traversal algorithm called topological sort is the fancy name for it, and it basically, yeah, it goes through that. It gives you a list of nodes in order where each node that you're given has no dependencies that have not been evaluated yet.
So, it works from effectively to use our tree terminology, from the leaf nodes to the root, potentially roots plural, of the graph, and each step is independent. So that's a lot of, like, fancy terminology, and getting a little bit of, like, computer science graph theory into here.
So, my, like, general heuristic is that graphs should be evaluated from the bottom up when you're trying to evaluate each piece independently. So, when you do that, you get to do each piece independently, as opposed to if you're evaluating from the top down. So, starting from the one thing that depends on everything else, well, it can't be shipped until all of its dependencies have been shipped.
And all the transitional dependencies can't be shipped until their dependencies have been shipped. And so, you end up being not able to ship anything until you've built the entire graph. And that's when you end up with, you know, a 2,000-line PR that took you multiple weeks and might be buggy. And it's going to take a long time to review. And it's just not what anybody wants.
STEPHANIE: I'm glad you brought this up because I think this is where I am really curious to get better at because oftentimes, when I am breaking down a complex task, it's quite hard for me to see all of the steps that need to happen. And so, you know, you maybe start out with that, like, top-level node, like, the task that needs to be done as you understand it immediately. And it's really hard to actually identify the dependencies and, like, the smaller pieces along the way. And because you're not able to identify that, you think that you do have to just do it all in one go.
JOËL: Yeah, that sort of root node is typically the overarching task, the goal of what you want to do. And a common, I think, scenario for something like this would be, let's say, you're doing a Rails upgrade. And so, that root node is upgrade Rails. And a common thing that you might want to do is say, okay, let's go to the gem file, upgrade Rails, see what breaks, and then just keep fixing those things. That's working from the top down.
And you're going to be in a long-running branch, and you're going to keep fixing things, fixing things, fixing things until you have found all the things but done all the things. And then you do a big bang upgrade that may have taken you weeks. As opposed to if you're working from the bottom up, you try to figure out, okay, what are all the subtasks? And that might take some exploration. You might not know upfront.
But then you might say, okay, here, I can upgrade RSpec versus a dependency, or I need to change the interface of this class and ship all these pieces one at a time. And then, the final step is flipping that upgrade in the gem file, saying, okay, now I've upgraded Rails from 4 to 5, or whatever the version is that you're trying to do.
STEPHANIE: I think you've really hit the nail on the head when it comes to trying to do something but not knowing what subtasks may compose of it and getting into that problem of, you know, having not broken it down, like, enough to really see all the dependencies.
And, you know, maybe this is a conversation [chuckles] for another episode, but the skill of breaking up those tasks and exploring what those dependencies are, and being able to figure them out upfront before you start to just do that upgrade and then see what happens, that's definitely an area that I want to keep investing in. And I'm sure other people would be really curious about, too, to help them make their jobs easier.
JOËL: I think one tip that I've learned that's really fun and that connects into all of this is sometimes you do end up with a cycle in your dependencies of tasks. A technique for breaking that up is a pattern that I have pitched multiple times on the show: the strangler fig pattern. And part of why it's so powerful is that it allows you to work incrementally by breaking up some of these cycles in your dependency graph.
And one of the lessons that I've learned from that is that just because you have sort of an initial set of subtasks and you have a graph of them doesn't mean that you can't change them. If you're following strangler fig, what you're actually doing is introducing one or more new subtasks to that graph. But the way you introduce them breaks up that cycle. So, you can always add new tasks or split up existing ones as you get a better understanding of the work you need to do. It's not something that is fixed or set in stone upfront.
STEPHANIE: Yeah, that's a really great tip. I think next time, what I really want to explore, you know, your heuristic of going from bottom up, yeah, sure, it sounds all fine and dandy. But how to get to a point where you're able to see everything at the bottom, right? And, like, when you are tasked, or you do start with the thing at the top, like, the end goal. Yeah, I'm sure that's something we'll explore [chuckles] another day.
JOËL: On that note, shall we wrap up?
STEPHANIE: Let's wrap up.
Show notes for this episode can be found at bikeshed.fm.
JOËL: This show has been produced and edited by Mandy Moore.
STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show.
JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter.
STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email.
JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week.
ALL: Byeeeeeee!!!!!!
ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.Support The Bike Shed

Aug 8, 2023 • 34min
396: Build vs. Buy
Joël has been fighting a frustrating bug where he's integrating with a third-party database, and some queries just crash. Stephanie shares her own debugging story about a leaky stub that caused flaky tests.
Additionally, they discuss the build vs. buy decision when integrating with third-party systems. They consider the time and cost implications of building their own integration versus using off-the-shelf components and conclude that the decision often depends on the specific needs and priorities of the project, including how quickly a solution is needed and whether the integration is core to the business's value proposition.
Ruby class instance variables
Build vs Buy by Josh Clayton
Sustainable Rails
Transcript:
STEPHANIE: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Stephanie Minn.
JOËL: And I'm Joël Quenneville. And together, we're here to share a bit of what we've learned along the way.
STEPHANIE: So, Joël, what's new in your world?
JOËL: My world has been kind of frustrating recently. I've been fighting a really frustrating bug where I'm integrating with a third-party database. And there are queries that just straight-up crash. Any query that instantiates an instance of an ActiveRecord object will just straight-up fail. And that's because before, we make the actual query, almost like a preflight query that fetches the schema of the database, particularly the list of tables that the database has, and there's something in this schema that the code doesn't like, and everything just crashes.
Specifically, I'm using an ODBC connection. I forget exactly what the acronym stands for, Open Database connection, maybe? Which is a standard put up by Microsoft. The way I'm integrating it via Ruby is there's a gem that's a C extension. And somewhere deep in the C extension, this whole thing is crashing. So, I've had to sort of dust off some C a little bit to look through. And it's not super clear exactly why things are crashing. So, I've spent several days trying to figure out what's going on there. And it's been really cryptic.
STEPHANIE: Yeah, that does sound frustrating. And it seems like maybe you are a little bit out of your depth in terms of your usual tools for figuring out a bug are not so helpful here.
JOËL: Yeah, yeah. It's a lot harder to just go through and put in a print or a debug statement because now I have to recompile some C. And, you know, you can mess around with some things by passing different flags. But it is a lot more difficult than just doing, like, a bundle open and binding to RB in the code.
My ultimate solution was asking for help. So, I got another thoughtboter to help me, and we paired on it. We got to a solution that worked. And then, right before I went to deploy this change, because this was breaking on the staging website, I refreshed the website just to make sure that everything was breaking before I pushed the fix to see that everything is working. This is a habit I've picked up from test-driven development. You always want to see your test break before you see it succeed.
And this is a situation where this habit paid off because the website was just working. My changes were not deployed. It just started working again. Now it's gotten me just completely questioning whether my solution fixes anything. The difficulty is because I am integrating [inaudible 03:20] third-party database; it's non-deterministic. The schema on there is changing rather frequently.
I think the reason things are crashing is because there's some kind of bad data or data that the ODBC adapter doesn't like in this third-party system. But it just got introduced one day; everything started breaking, and then somehow it got removed, and everything is working again without any input or code changes on my end. So, now I don't trust my fix.
STEPHANIE: Oh no. Yeah, I would struggle with that because your reality has come crashing down, [laughs] or how you understood reality. That's tough. Where do you think you'll go from here? If it's no longer really an issue in this current state of the schema, is it worth pursuing further at this time?
JOËL: So, that's interesting because it turns into a prioritization problem. And for this particular project, with the deadlines that we have, we've decided it's not worth it. I've opened up a PR with my fix, with some pretty in-depth documentation for why I thought that was the fix and what I think the underlying problem is. If this shows up again in the next few days, I'll have that PR that I can pull in and see if it fixes things, and if it doesn't, I'll probably just close that PR, but it'll be available for us if we ever run into this again.
I've also looked at a few potential mitigating situations. Part of the problem is that this is a, like, massive system. The Rails app that I'm using really doesn't need to deal with this massive database. I think there's, you know, almost 1,000 tables, and I really only care about a subset of tables in, like, one underlying schema. And so, I think by reducing the permissions of my database user to only those tables that I care about, there's a lower chance of me triggering something like this.
STEPHANIE: Interesting. What you mentioned about, you know, having that PR continue to exist will be really helpful for future folks who might come across the same problem, right? Because then they can see, like, all of the research and investigation you've already done. And you may have already done this, but if you do think it's a schema issue, I'm curious about whether the snapshot of the schema could be captured from when it was failing to when it has magically gotten fixed. And I wonder if there may be some clues there for some future investigator.
JOËL: Yeah. I'm not sure what our backup situation is because this is a third-party system, so I'd have to figure out what things are like in the admin interface there. But yeah, if there is some kind of auditing, or snapshots, or backups, or something there, and I have rough, you know, if I know it's within a 24-hour period, maybe there's something there that would tell me what's happening.
My best guess is that there's some string that is longer than expected or maybe being marked as a CHAR when it should be a VARCHAR, or maybe something that's not a non-UTF-8 encoded character, or something weird like that. So, I never know exactly what was wrong in the schema. There's some weird string thing happening that's causing the Ruby adapter to blow up.
STEPHANIE: That also feels so unsatisfying [laughs] for you. I could imagine.
JOËL: Yeah, there's no, like, clean resolution, right? It's a, well, the bug is gone for now. We're trying to make it less likely for it to pop up again in the future. I'm trying to leave some documentation for the next person who's going to come along, and I'm moving forward, fingers crossed. Is that something you've ever had to do on one of your projects?
STEPHANIE: Given up? Yes. [laughter] I think I have definitely had to learn how to timebox debugging and have some action items for when I just can't figure it out. And, you know, like we mentioned, leaving some documentation for the next person to pick up, adding some additional logging so that maybe we can get more clues next time. But, you know, realizing that I do have to move on and that's the best that I can do is really challenging.
JOËL: So, you used two words here to describe the situation: one was giving up, and the other one was timebox. I think I really like the idea of describing this as timeboxing. Giving up feels kind of like, defeatist. You know, there's so many things that we can do with our time, and we really have to be strategic with how we prioritize. So, I like the idea of describing this as a timeboxing situation.
STEPHANIE: Yeah, I agree. Maybe I should celebrate every time that I successfully timebox something [laughs] according to how I planned to. [laughs]
JOËL: There's always room to extend the timebox, right?
STEPHANIE: [laughs] It's funny you bring up a debugging mystery because I have one of my own to share today. And I do have to say that it ended up being resolved, [chuckles] so it was a win in my book. But I will call this the case of the leaky stub.
JOËL: That sounds slightly scary.
STEPHANIE: It really was. The premise of what we were trying to figure out here was that we were having some flaky tests that were failing with a runtime error, so that was already kind of interesting. But it was quickly determined it was flaky because of the tests running in a certain order, so--
JOËL: Classic.
STEPHANIE: Right. So, I knew something was happening, and any tests that came after it were running into this error. And I was taking a look, and I figured out how to recreate it. And we even isolated to the test itself that was running before everything else, that would then cause some problems. And so, looking into this test, I saw that it was stubbing the find method on an ActiveRecord model.
JOËL: Interesting.
STEPHANIE: Yeah. And the stubbed value that we were choosing to return ended up being referenced in the tests that followed. So, that was really strange to me because it went against everything I understood about how RSpec cleans up stubs between tests, right?
JOËL: Yeah, that is really strange.
STEPHANIE: Yeah, and I knew that it was referencing the stub value because we had set a really custom, like, ID value to it. So, when I was seeing this exact ID value showing up in a test that seemed totally unrelated, that was kind of a clue that there was some leakage happening.
JOËL: So, what did you do next?
STEPHANIE: The next discovery was that the error was actually raised in the factory setup for the failing tests and not even getting to running the examples at all. So, that was really strange. And digging into the factories was also its own adventure because there was a lot of complexity in the factories. A lot of them used hooks as well that then called some application code. And it was a wild goose chase.
But ultimately, I realized that in the factory setup, we were calling some application code for that model where we had stubbed the find, and it had used the find method to memoize a class instance variable.
JOËL: Oh no. I can see where this is going.
STEPHANIE: Yeah. So, at some point, our model.find() returned our, you know, stub value that we had wanted in the previous test. And it got cached and just continued to leak into everything else that eventually would try to call that memoized method when it really should have tried to do that look-up for a separate record.
JOËL: And class instance variables will persist between tests as long as they're on the same thread, right?
STEPHANIE: Yeah, as far as I understand it.
JOËL: That sounds like a really frustrating journey. And then that moment when you see the class instance variable, and you're like, oh no, I can't believe this is happening.
STEPHANIE: Right? It was a real recipe for disaster, I think, where we had some, you know, really complicated factories. We had some sneaky caching issues, and this, you know, totally seemingly random runtime error that was being raised. And it was a real wild goose chase because there was not a lot of directness in going down the debugging path. I feel like I went around all over the codebase to get to the root of it. And, in the end, you know, we were trying to come up with some takeaways.
And what was unfortunate was that you know, like, normally, stubbing find can be okay if you are, you know, really wanting to make sure that you are returning your mocked value that you may have, like, stubbed some other stuff on in your test. But because of all this, we were like, well, should we just not stub find on this really particular model? And that didn't seem particularly sustainable to make as a takeaway for other developers who want to avoid this problem.
So, in the end, I think we scoped the stub to be a little more specific with the arguments that we wanted to target. And that was the way that we went forward with the particular flaky test at hand.
JOËL: It sounds like the root cause of the problem was not so much the stub as it was the fact that this value is getting cached at the class level. Is that right?
STEPHANIE: Yes and no. It seems like a real pain for running the tests. But I'm assuming that it was done for a good reason in production, maybe, maybe not. To be fair, I think we didn't need to cache it at all because it's calling a find, which is, you know, should be pretty quick and doesn't need to be cached. But who knows? It's hard to tell. It was really old code. And I think we were feeling also a little nervous to adjust something that we weren't sure what the impact would be.
JOËL: I'm always really skeptical of caching. Caching has its place. But I think a lot of developers are a little too happy to introduce one, especially doing it preemptively that, oh well, we might need a cache here, so why not? Let's add that. Or even sometimes, just as a blind solution to any kind of slowness, oh, the site is slow; let's throw a cache here and hope for the best.
And the, like, bedrock, like, rule zero of any kind of performance tuning is you've got to measure before and after and make sure that the change that you introduce actually makes things better. And then, also, is it better enough speed-wise that you're willing to pay any kind of costs associated to maintaining the code now that it's more complex? And a lot of caches can have some higher carrying costs.
STEPHANIE: Yeah, that's a great point. This debugging mystery an example of one of them.
JOËL: How long did it take you to figure out the solution here?
STEPHANIE: So, like you, I actually was on a bit of the incorrect path for a little while. And it was only because this issue affected a different flaky test that someone else was investigating that they were able to connect the dots and be like, I think these, you know, two issues are related. And they were the ones who ultimately were able to point us out to the offending test if you will. So, you know, it took me a few days. And I imagine it took the other developer a few days. So, our combined effort was, like, over a week.
JOËL: Yep. So, for all our listeners out there, you just heard that Stephanie and I [laughs] both went on multi-day debugging journeys. That happens to everyone. Just because we've been doing this job for years doesn't mean that every bug is, like, a thing that we figure out immediately.
So, separately from this bug that I've been working on, a big issue that's been front of mind for me on this project has been the classic build versus buy decision. Because we're integrating with a third-party system, we have to look at either building our own integration or trying to use some off-the-shelf components. And there's a few different levels of this.
There are some parts where you can actually, like, literally buy an integration and think through some of the decisions there. And then there's some situations where maybe there's an open-source component that we can use. And there's always trade-offs with both the commercial and the open-source situation. And we have to decide, are we willing to use this, or do we want to build our own? And those have been some really interesting discussions to have.
STEPHANIE: Yeah. I think you actually expanded this decision-making problem into a build versus buy versus open source because they are kind of, you know, really different solutions with different outcomes in terms of, you know, maintenance and dependencies, right? And that all have, like, a little bit of a different way to engage with them.
JOËL: Interesting. I think I tend to think of the buy category, including both like commercial off-the-shelf software and also open-source off-the-shelf software, things that we wouldn't build custom for ourselves but that are third-party components that we can pull in.
STEPHANIE: Yeah, that's interesting because I had a bit of a different mental model because, in my head, when you're buying a commercial solution, you, you know, are maybe losing out on some opportunities for customization or even, like, forking it on your own. So, with an open-source solution, there could be an aspect of making it work for you. Whereas for a commercial solution, you really become dependent on that other company and whether they are willing to cater [laughs] to your needs or not.
JOËL: That's fair. For something that's closed-source where you don't actually have access to the code, say it's more of a software as a service situation, then, yeah, you're kind of locked in and hoping that they can provide the needs that you have. On the flip side, you are generally paying for some level of support. The quality of that varies sometimes from one vendor to another. But if something goes wrong, usually, there's someone you can email, someone you can call, and they will tell you how to fix the problem, or they will fix it on their end.
STEPHANIE: For the purposes of this conversation, should we talk about the differences, you know, building yourself or leaning on an existing built-out solution for you?
JOËL: The project I'm working on is integrating with a Snowflake data warehouse, which is an external place that stores data accessible through something SQL-like. And one of the things that's attractive about this is that you can pull in data from a variety of different sources, transform it, and have it all stored in a kind of standardized structure that you can then integrate with. So, for pulling data in, you can build your own sort of ingestion pipeline, if you want, with code, and their APIs, and things.
But there are also third-party vendors that will give you kind of off-the-shelf components that you can use for a lot of popular other data sources that you might want to pull. So, you're saying; I want to pull from this external service. They've probably got a pre-built connector for it. They can also do things like pull from an arbitrary Postgres database on some other server if that's something you have access to.
It becomes really attractive because all you need to do is create an account on this website, plug in a few, like, API keys and URLs. And, all of a sudden, data is just flowing from one third-party system into your Snowflake data Warehouse, and it all just kind of works. And you don't have to bother with APIs, or ODBC, or any of that kind of stuff.
STEPHANIE: Got it. Yeah, that does sound convenient. As you were talking about this, I was thinking about how if I were in the position of trying to decide how to make that integration happen, the idea of building it would seem kind of scary, especially if it's something that I don't have a lot of expertise in.
JOËL: Yeah, so this was really interesting. In the beginning of the project, I looked into a little bit of what goes into building these, and it's fairly simple in terms of the architecture. You just need something that writes data files to typically something like an S3 bucket. And then you can point Snowflake to periodically pull from that bucket, and you write an import script to, you know, parse the columns and write them to the right tables in the structure that you want inside Snowflake.
Where things get tricky is the actual integration on the other end. So, you have some sort of third-party service. And now, how do you sort of, on a timer maybe, pull data from that? And if there are data changes that you're synchronizing, is it just all append-only data? Or are you allowing the third-party service to say, "Hey, I deleted this record, and you should reflect that in Snowflake?" Or maybe dealing with an update. So, all of these things you have to think about, as well as synchronization.
What you end up having to do is you probably boot up some kind of small service and, you know, maybe this is a small Ruby app that you have on Heroku, maybe this is, like, an AWS Lambda kind of thing. And you probably end up running this every so many seconds or so many minutes, do some work, potentially write some files to S3. And there's a lot of edge cases you have to think about to do it properly. And so, not having to think about all of those edge cases becomes really enticing when you're looking to potentially pay a third party to do this for you.
STEPHANIE: Yeah, when you used the words new service, I bristled a little bit [laughs] because I've definitely seen this happen maybe on a bit of a bigger scale for a tool or solution for some need, right? Where some team is formed, or maybe we kind of add some more responsibilities to an existing team to spin up a new service with a new repo with its own pipeline, and it becomes yet another thing to maintain. And I have definitely seen issues with the longevity of that kind of approach.
JOËL: The idea of maintaining a fleet of little services for each of our integrations seemed very unappealing to me, especially given that setting something like this up using the commercial approach probably takes 30 minutes per third-party service. There's no way I'm standing up an app and doing this whole querying every so many minutes, and getting data, and transforming it, and writing it to S3, and addressing all the edge cases in 30 minutes. And it's building something that's robust.
And, you know, maybe if I want to go, like, really low tech, there's something fun I could do with, like, a Zapier hook and just, like, duct tape a few services together and make this, like, a no-code solution. I still don't know that it would have the robustness of the vendor. And I don't think that I could do it in the same amount of time.
STEPHANIE: Yeah. I like the keyword robustness here because, at first, you were saying, like, you know, this looked relatively small in scope, right? The code that you had to write. But introducing all of the variables of things that could go wrong [laughs] beyond the custom part that you actually care about seemed quite cumbersome.
JOËL: I think there's also, at this point, a lot of really interesting prioritization questions. There are money questions, but there are also time questions you have to think about. So, how much dev time do we want to devote upfront to building out these integrations? And if you're trying to move fast and get a proof of concept out, or even get, like, an MVP out in front of customers, it might be worth paying more money upfront to a third-party vendor because it allows you to ship something this week rather than next month.
STEPHANIE: Yeah. The "How soon do you need it?" is a very good question to ask. Another one that I have learned to include in my arsenal of, you know, evaluating this kind of stuff comes from a thoughtbot blog by Josh Clayton, where he, you know, talks about the build versus buy problem. And his takeaway is that you should buy when your business is not dependent on it.
JOËL: When it's not part of, like, the core, like, value-add that your business is doing. Why spend developer time on something that's not, like, the core thing that your product is when you can pay someone else to do it for you? And like we said earlier, a lot of that time ends up being sunk into edge cases and robustness and things like that to the point where now you have to build an expertise in a, like, secondary thing that your business doesn't really care about.
STEPHANIE: Yeah, absolutely. I think this is also perhaps where very clear business goals or a vision would come in handy as well. Because if you're considering building something that doesn't quite support that vision, then it will likely end up continuing to be deprioritized over the long term until it becomes this thing that no one is accountable for maintaining and caring for.
And just causes a lot of, honestly, morale issues is what I've seen when some service that was spun up to try to solve a particular problem is kind of on its last legs and has been really neglected, and no one wants to work on it. But it ends up causing issues for the rest of the development team. But then they're also really focused on initiatives that actually do provide the business value. That is a really hard balancing act that I've seen teams struggle with.
JOËL: Earlier this year, we were talking about the book Sustainable Rails. And it really hammers home the idea of a carrying cost for the code, and I think that's exactly what we're talking about here. And that carrying cost can be time and money. But I like that you also mentioned the morale effects. You know, that's a carrying cost that just sort of depresses the productivity of your team when morale is low.
STEPHANIE: Yeah, absolutely. I'm curious if we could discuss some of the carrying costs of buying a solution and where you've seen that become tricky.
JOËL: The first thing to look at is the literal cost, the money aspect of things. And I think it's a really interesting situation for the business models for these types of Snowflake connectors because they typically charge by the amount of data that you're transmitting, so per row of data that you're transmitting. And so, that cost will fluctuate depending on whether the third-party service you're integrating with is, like, really chatty or not.
When you contrast that to building, building typically has a relatively fixed cost. It's a big upfront cost, and then there's some maintenance cost to go with it. So, if I'm building some kind of integration for, let's say, Shopify, then there's the cost I need to build up front to integrate that. And if that takes me, I don't know, a week or two weeks, or however long it is, you know, that's a pretty big chunk of time. And my time is money.
And so, you can actually do the math and say, "Well, if we know that we're getting so many rows per day at this rate from the commercial vendor, how many weeks do we have to pay for the commercial one before we break even and it becomes more expensive than building it upfront, just in terms of my time?" And sometimes you do that math, and you're like, wow, you know, we could be going on this commercial thing for, like, two years before we break even. In that case, from a purely financial point of view, it's probably worth paying for that connector.
And so, now it becomes really interesting. You say, okay, well, which are the connectors that we have that are low volume, and which are the ones that are high volume? Because each of them is going to have a different break-even point. The ones that you break even after, you know, three or four weeks might be the ones that become more interesting to have a conversation about building. Whereas some of the others, it's clearly not worth our time to build it ourselves.
STEPHANIE: The way you described this problem was really interesting to me because it almost sounds like you found the solution somewhere in the middle, potentially, where, you know, you may try building the ones that are highest priority, and you end up learning a lot from that experience, right? That could make it easier or at least, like, set you up to consider doing that moving forward in the future if you find, like, that is what is valuable.
But it's interesting to me that you kind of have the best of both worlds of, like, getting the commercial solutions now for the things that are lower value and then doing what you can to get the most out of building a solution.
JOËL: Yeah. So, my final recommendation ended up being, let's go all commercial for now. And then, once we've built out something, and because speed is also an issue here, once we've built out something and it's out with customers, and we're starting to see value from this, then we can start looking at how much are we paying per week for each of these connectors? And is it worth maybe going back and building our own for some of these higher-volume connectors? But starting with the commercial one for everything.
STEPHANIE: Yeah, I actually think that's generally a pretty good path forward because then you are also learning about how you use the commercial solution and, you know, which features of it are critical so that if you do eventually find yourselves, like, maybe considering a shift to building in-house, like, you could start with a more clear MVP, right? Because you know how your team is using an existing product and can focus on the parts that your business are dependent on.
JOËL: Yeah, it's that classic iterative development style. I think here it's also kind of inspired by a strategy I typically use for performance, which is make it work before you try to make it fast. And, actually, make it work, then profile, then measure, find the hotspots, and then focus on making those things fast. So, in this case, instead of speed, we're talking about money. So, it's make it work, then profile, find the parts that are expensive, and make the trade-off of, like, okay, is it worth investing into making that part less expensive in terms of resources?
STEPHANIE: I like that as a framework a lot.
JOËL: A lot of what we do as programmers is optimization, right? And sometimes, we're optimizing for execution time. Sometimes we're optimizing for memory cost, and sometimes we're optimizing for dollars.
STEPHANIE: Yeah, that's really interesting because, with the buy solution, you know very clearly, like, how much the thing will cost. Whereas I've definitely seen teams go down the building route, and it always takes longer than expected [laughs], and that is money, right? In terms of the developer's time, for sure.
JOËL: Yeah, definitely, like, add some kind of multiplier when you're budgeting out that build alternative because, quite likely, there are some edge cases that you haven't thought about that the commercial partner has, and you will have to spend more time on that than you expected.
STEPHANIE: Yeah, in addition to whatever opportunity cost of not working on something that is driving revenue for the business right now.
JOËL: Exactly.
STEPHANIE: So, the direction of this conversation ended up going kind of towards, like, what is best for the team at, like, a product and company level. But I think that we make these decisions a lot more frequently, even when it comes to whether we pull in a gem or, you know, use an open-source tool or not. And I would be really interested in discussing more of that in another episode.
JOËL: Yeah. That gets into some controversial takes, right? It's the evergreen topic of: do we build it ourselves, or do we pull in some kind of third-party package?
STEPHANIE: Something for the future to look forward to. On that note, shall we wrap up?
JOËL: Let's wrap up.
STEPHANIE: Show notes for this episode can be found at bikeshed.fm.
JOËL: This show has been produced and edited by Mandy Moore.
STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show.
JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter.
STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email.
JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week.
ALL: Byeeeeeeeee!!!!!
ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.Support The Bike Shed

Aug 1, 2023 • 31min
395: Human Connection in a Virtual (Work) World
Stephanie had a small consulting win: saying no to a client. GeoGuessr is all the rage for thoughtbot's remote working culture, which leads to today's topic of forming human connections in a virtual (work) environment.
GeoGuessr
Strategies for saying no by Elle Meredith
NYT Let’s Ignore Each Other in the Same Room
Random question generator
Transcript:
JOËL: And this is just where it ends.
[laughter]
Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville.
STEPHANIE: And I'm Stephanie Minn. And together, we're here to share a bit of what we've learned along the way.
JOËL: So, Stephanie, what's new in your world?
STEPHANIE: So, I have a small consulting win, or even just a small, like, win as a human being [laughs] that I want to share, which is that I feel good about a way that I handled saying no to a stakeholder recently. And, you know, I really got to take them where I can get it because that is so challenging for me. But I feel really glad because we ended up kind of coming out the other side of it having a better understanding of each other's goals and needs.
And so, basically, what happened was I was working on a task, and our product owner on our team asked me if it could be done by next week. And immediately, I wanted to say, "Absolutely not." [laughs] But, you know, I took a second and, you know, I had the wherewithal to ask why. You know, I was kind of curious, like, where was this deadline coming from? Like, what was on her radar that, like, wasn't on mine?
And she had shared that, oh, you know, if we were able to get it out before this big launch, she was thinking that it actually might make our customer support team's lives easier because we were kind of taking away access to something before some new features rolled out. And, you know, there might be some customers who would complain. And with that information, you know, that was really helpful in helping me understand. And I'm like, yeah, like, that seems like a helpful thing to know, so I could try to strive for it. Because I also, like, want to make that process go easier as well.
But I told her that I'd let her know because I honestly wasn't sure if it was possible to do by next week. And after a little bit of, you know, more digging, kind of seeing how my progress was going, in the end, I had to say that I didn't feel confident that we could finish it in time for that deadline because of the other risks, right? Like, I didn't want to just release this thing without feeling good about the plan that we had. And so, that was my small, little win in saying no, and I feel very proud of myself for it.
JOËL: I'm proud of you too. That's not easy to just do in the first place, and then to do it well is a whole other level. It sounds, though, that you came out of the other side with the client with almost, like, a better relationship.
STEPHANIE: Yeah, I think so. In general, you know, I really struggle when people do end up getting into that debate of, like, "Well, I need this." And someone else says, "Well, I need this other thing." And, you know, at some point, it kind of gets a bit unproductive, right? But I think this was a very helpful way for me to see a path forward when maybe we, like, have different priorities. But, like, can we better understand each other and the impact of them to ultimately, like, make the best decision?
The other thing that I wanted to share that I learned recently was there was a recent RailsConf talk by Elle Meredith, and it was about strategies to say no, and I watched it. And one really cool thing that I learned was that the word priority, you know, when it was first created, it actually didn't really have, like, a plural form. There was really only ever, like, a singular priority. And it wasn't until, I think, you know, the recent century or something like that, that people started to use it in a plural form. And that was really enlightening to me.
I think it made me rethink the word and how I use it, and it made a lot of sense, too. Because at any given moment, you know, really, you can't be doing more than one thing; I mean, you can try. I know that I have been guilty of multitasking. But that, you know, doesn't always serve me. I never end up doing all of the things that I'm trying to do well. And I would be really curious to kind of, you know, when I do feel that urge, like, think a little bit about, like, what is the one thing that I should be doing right now that is the highest priority?
JOËL: I would definitely second that recommendation for this talk. I actually got to see it live at RailsConf, and it was excellent.
STEPHANIE: So, Joël, what's new in your world?
JOËL: I got to participate in a really fun event at thoughtbot today. We got together with some other people on the Boost Team and played a few rounds of GeoGuessr. And for those who are not familiar with this game, it drops you randomly somewhere in the world in Google Street View. You can move around. And there's a timer, and you have to drop a pin on a map where you think you are.
So, you're walking through the streets, and you're like, okay, well, I don't know this language. I'm not sure where we're going. You know, with the vibes going here, I'll bet, you know, this looks like maybe southern China, and then you drop a pin. And oh no, turns out it was actually Singapore. And there's all these little hints and things. People who are really into it have learned all these tricks, and they can be really good. Sara Jackson, who is our resident GeoGuessr expert, is excellent at this. But it was a good time.
STEPHANIE: Yeah, it was really fun. I liked that we played a cooperative mode where we were all kind of helping each other out. And so, maybe someone is, like, exploring on the map and sees a street sign and is like, "Oh, like, that looks like this language." And someone else is like, "Oh yeah, like, that is that." Or like, "No, I think it's actually this other language," and sharing all of the different, like, pieces of information that we're finding to get closer and closer to what it might be.
And then we celebrate whoever ends up getting the closest because, at some point, it's kind of just, like, just a luck of the pin, right? Where maybe you happen to click on, like, the right place. But it's always really exciting when we're like, wow, like, Sara was only 500 kilometers away in finding the exact place that we were served. So, I had a good time as well.
JOËL: So, speaking of cooperative events, this was a work event that we did. We just got together and played a game. And, for me, that was a really fun way to connect with some of my colleagues. I'm curious, what are your thoughts on things that you've seen done well in companies that are remote-first that really foster a sense of connection and community among a team?
STEPHANIE: I think this worked especially well today because it was kind of scheduled in regular time that we have as a team to me. And sometimes, you know, the meeting topics are a bit more work-focused. But what I really like is that anyone on the team can host one of these meetings. We have them biweekly, and we just call them Boost biweeklies. Boost is the team that Joël and I are on.
JOËL: Naming is the hardest problem in computer science.
STEPHANIE: It really is. But I really like that people can bring, you know, a little bit of their own flavor to this meeting. So, whoever is host just kind of comes up with something to do. And sometimes it's like show and tell. You know, other times it is more of like, you know, what's the update on some of the projects that we're doing? Other times, it's the Spicy Takes Lightning Talks that we've kind of mentioned on the podcast before. And yeah, it is just a really nice, like, time for us to get together.
And I also feel like I learn something about my co-workers every time that we meet, whether it's the person who is hosting the meeting and kind of where their interests are. I think someone even did, like, chair yoga once and guided the team in doing that. Or because they are more casual, right? Sometimes we just play a game, and I really enjoy that nice break in my day.
JOËL: Do you find that the particular style of these meetings makes you feel more connected to your colleagues? Would you prefer just kind of game day one, like we had today, versus maybe, like, lightning talks or a presentation on security or something like that?
STEPHANIE: I actually think the diversity is what makes it special. I get to see, you know, a bunch of different sides of my co-workers and, you know, some days, the topic is a little more serious, and that can be really connecting. Another Boost Team member had hosted a biweekly where we kind of shared the challenges of, like, consulting work and, like, onboarding onto a new project and sharing what might be difficult and, like, how we might be feeling when we do join a new project.
And I think that was really helpful because it was very validating for something that I thought, like, maybe I felt a little bit more alone in. And the tone was a little bit more, like, earnest and serious. But I came away with it feeling very supported by my team, right? And other times, it is just silliness and fun [laughs], which, you know, is also important. Like, we need to have fun every once in a while.
JOËL: That's awesome. Do you feel like when you go to these meetings, you're looking more for knowledge or looking more for connection?
STEPHANIE: I think both because knowledge sharing is also, you know, can be really helpful. Like, I have enjoyed learning that, you know, so and so is, like, a GeoGuessr expert, Sara, right? And so, if I ever, like, find myself needing [chuckles] someone to go to about my Google Street View or world geography questions, I know that I can go to her. And, like, knowing that about her, like, makes me feel more connected to her. So, I think both are true.
So, we have been talking about a meeting style form of connecting in a remote workplace, but I'm really curious about your thoughts on asynchronous versus synchronous communication and how you find connection with a format that is more asynchronous, not just, you know, being in a meeting together.
JOËL: That's really challenging. I think I personally find that something that's mostly synchronous with maybe a little bit of a lag works pretty well for me, so something like Slack, where it's not exactly real-time because someone could take some time to come back to me. But for working hours overlap, there's likely some close-to-synchronous conversation happening.
But, you know, I can still get up and, you know, refill my cup of coffee, or it's not quite like I'm sitting in front of a camera. So, I think that, for many things, hits the sweet spot for myself. But there's definitely some things where I think you want a higher, like, information density. And that's, I think, where the synchronous face-to-face meeting really shines.
STEPHANIE: Information density. I haven't heard that phrase before, but I like it.
JOËL: The idea being, you know, how much information or how many words are you sharing back and forth, you know, per minute or something like that. And when you're talking on a call, you can do a lot more of that than you can going back and forth over Slack or writing an email.
STEPHANIE: So, I would say that at thoughtbot, we have a pretty asynchronous Slack culture, which I think can be quite different from other, you know, places I've worked at before or other Slack spaces that I've seen. And I actually find it a little bit harder to engage in that way. We have a dev channel where, you know, people chat about different technical topics. And sometimes, you know, those threads go, like, 40 replies long. And I think you tend to engage a lot more in those.
And I'm curious, like, does that scratch the itch for you in terms of that perfect, like, async, kind of some amount of lag for you to be doing other things, kind of doing your work, but then being able to come back and pick up the conversation where I left off?
JOËL: Yes, that is really nice because, you know, maybe I have a meeting or something, and I'm not there when the conversation starts, but I don't miss out. And I get to join in, you know, maybe 30 minutes after everyone else. You know, sometimes you don't want to just, like, restart a conversation that's happened and is done. But some of these things will kind of be going on and off all day. And those can be really fun, especially sometimes, like, a new person joins the thread and brings in a totally new perspective or a new angle that kind of, like, breathes new life into it and kind of gives everyone a new perspective.
STEPHANIE: Nice. I also think there's something to the idea of seeing more people engage with something that then invites other people to engage with it.
JOËL: I would agree with that. It's definitely exciting to see a thread, and it's not like, oh, it's empty, and I'm the only one who's put a response in here. When there is a lot of back and forth, you can almost feel the excitement. And that gets me hyped to, like, keep it going.
STEPHANIE: At a previous workplace in our Slack, we had a, like, virtual Jeopardy channel.
JOËL: Ooh.
STEPHANIE: And so, there was a little Jeopardy bot. And I guess whenever someone, you know, had a low on what they were doing, they would just start, you know, tagging the bot to pose a question. And anyone can answer, right? But once you kind of got the ball rolling, you would see other people start playing as well. And it would get really active for segments of 30 minutes or so.
And I always really enjoyed that because, yeah, it was a way for me to remember like, oh yeah, there's, like, other people also, like, typing away on their little keyboards, and we're all here together. But it was really interesting to see, like, when someone got it rolling, like, oh, other people, like, joined in.
JOËL: Yeah, being able to see small things like that can really build a sense of connection, even if you're not yourself directly participating.
STEPHANIE: Yeah. I think another thing I've been trying out lately is letting people know that I'm in a meeting space and offering to virtually co-work. So, you know, during the early days of when thoughtbot went remote, we had a lounge virtual meeting space for people to hang out with and, you know, get that face time that they weren't getting anymore since we weren't in the office. And, you know, I think that has kind of decreased in terms of engagement over, you know, several years now. And obviously, people have a lot of meeting fatigue and stuff like that.
But I was kind of in a mood to revive it a little bit because, yeah, I kind of got over the meeting fatigue and was wanting more face time with people. And the unfortunate thing, though, is that, like, no one was showing up to this room anymore. So, you know, even if someone wanted to hang out in it, you know, they go in. They see no one's there, you know, maybe they stay for a few minutes, but then they're like, okay, well, I'm just going to leave now.
And a couple of thoughtboters and I have been trying to revive it where we'll post in our general channel, like, "Hey, like, I'm in this meeting room. Like, come hang out for the next hour if you would like." And that's been working well for me. I have had a few, like, really nice lounge, virtual co-working hangout sessions. Even if one person shows up, honestly, like, that fulfills my want to just, like, speak to another human. [laughs]
JOËL: What does virtual co-working look like? Are you just kind of each doing work, but you've got a video camera on, and you're just aware of the presence of someone else? Do you kind of have, like, random breaks where you talk? What is that experience like?
STEPHANIE: Oh yeah, that's a good question. I have to say; for me, I'm just talking to the other [laughs] person at that point. I'm not really doing a whole lot of work. And, you know, in some ways, I almost think that, like, in those moments, I am really wanting to chat with someone and, like, that's okay, right?
JOËL: It's like a virtual water cooler for you.
STEPHANIE: Yeah, exactly. Like, that would be the moment if I were working in office that I would wander into the kitchen looking for a snack but also an unsuspecting victim to start [laughs] a conversation with.
JOËL: I feel you. I feel you. I have absolutely done that.
STEPHANIE: Yeah. And that's actually what makes me feel a little less guilty about it. Because, you know, when I was working in the office, like, that was such a big part of my day, and it's kind of what kept me motivated. And at home, I do find myself, like, a lot more productive. In fact, like, I think I am because I'm, you know, not spending that time wandering into the kitchen. But at what cost? [laughs] At the cost of, like, me feeling very, like, lonely and, like, kind of burnt out at the end of the day.
So, injecting my day with some of these moments, I think, is important to me. And also, again, like, I know that I'm being really productive in my, like, heads-down-time that I want to, you know, allow myself to just like, get that dose of connection.
JOËL: I know, for me, when we were doing things like this in person as well, those conversations that happen, yes, there's some random, frivolous stuff, but sometimes, it is a conversation related to work that I'm doing. Because, you know, someone who's not on my project is like, "Hey, how's your project going?" Or whatever. I'm like, "Oh, well, I'm, you know, doing this ODBC connection, and I'm kind of stuck." And, you know, we kind of talk about a few things. It's like, "Oh, did you know about this gem?" And it's like, "Wait, why didn't I talk to you earlier? Because this totally solves my problem."
STEPHANIE: Yeah, I think that being a sounding board is so valuable as well. So, I guess I enjoy virtual co-working, not necessarily, you know, us, like, sitting together and doing our work separately. Though I know that there's value in that, especially in real life. Like, I remember reading an article. I'll try to find it and link it. But the idea of just, like, sharing space with someone can be, like, a form of bonding.
But I do really enjoy just hearing about what other people are working on and just kind of, like, asking questions about it, right? And maybe we do take away, like, a new perspective or, like, have some insights about, like, the work itself. And, yeah, we don't really get that when we're working remotely by ourselves because there's no one to turn to and be like, "Hey, what do you think about this problem?"
JOËL: I love how no matter what the topic is that we're discussing on this show, you always have a book or an article or something that you've read that you can reference. And I think that's amazing.
STEPHANIE: Thank you.
JOËL: So, you're talking about things that have really helped you feel a deeper sense of connection. I had a realization recently about the power of physical items. In particular, as consultants, sometimes we work with clients who, for security reasons, want us to work on a dedicated laptop for this particular client. And so, we'll have clients maybe—well, now that we're remote—ship us a laptop, and we work on that laptop when we're doing client stuff, and then on our thoughtbot laptops when we're doing thoughtbot things.
And when I've been on clients like that, I have felt much more isolated from the thoughtbot team. And just, like, physically switching over to the thoughtbot laptop, all of a sudden, gives me that feeling of connection. And there's something I can't quite explain about the power of the physical item. And, say, I'm working on the thoughtbot laptop today with, you know, thoughtbot Slack in the background or whatever, and I feel more connected to my colleagues.
STEPHANIE: Yeah, that is really curious. Did you also have thoughtbot communication channels open in your client laptop during that time?
JOËL: I did, and yet still felt more separation.
STEPHANIE: Yeah, that's really interesting. The way you're describing it, it was almost like, you know, the main laptop that you work with, with your, like, all of the settings that you like, all of your little shortcuts, you know, the autocomplete to the whatever, like, channels of communication that you are used to seeing. In some ways, that almost feels like home a little bit. And I wonder if working on a client laptop almost kind of feels like, you know, being in a stranger's house, right?
JOËL: There's definitely an element of that. Yeah, all the little things I've fine-tuned, some of the productivity software I have on there that are just, you know, I can one by one set them up on the client laptop, depending on permissions. But yeah, it's never quite the same.
STEPHANIE: So, when you are in a situation where you're mostly working from a client laptop and maybe embedded in their Slack workspace, embedded in their team, how do you go about investing in connection with your client team?
JOËL: So, you know what's kind of weird? Is that when I'm on a client laptop, I feel less connected to my colleagues at thoughtbot, but the reverse is not necessarily true. I don't feel more connected to colleagues on a client team on a client laptop than I would on my thoughtbot laptop. So, I'm not exactly sure what the psychology is going on there. But I feel kind of most connected to both when I'm working on my thoughtbot laptop, which is perhaps a bit strange.
STEPHANIE: Oh, yeah, that is interesting. I think, in general, there's an aspect of joining a new client team and trying to figure out the culture there and how you might engage with it, right? And how what you bring to the table kind of fits in with how they do things, and how they talk about things, and how they behave. In some ways, it's kind of, like, you know, an outsider joining this, like, in-group, right? So, I've definitely realized that the ways that I engage and feel connected at thoughtbot, like, may or may not work for the client team that I'm joining.
JOËL: Yeah. And onboarding onto a client team is not just a technical exercise, right? It's also a social process where you want to get to know the other people on your team, get to sort of integrate into the way they work, their processes, hopefully, build a little bit of, like, personal connection with individuals because all of those are going to help me do my job better tomorrow, and the day after, and the week after that.
STEPHANIE: Yeah. I had mentioned previously that one thing that I've been enjoying on my client team is our daily sync question. So, a random question will be generated, you know, like, "What are you eating for dinner today?" Or, like, "What are you looking forward to this weekend?" And folks are able to share. And the fun thing is that sometimes the answer to the question is longer than their work update itself.
JOËL: Nice.
STEPHANIE: But that is actually the, you know, the beauty of it because we all just, like, get to laugh and get to, you know, chime in. And I'm like, "Oh yeah, like, that sounds delicious, like, what you're eating for dinner tonight." But, like, that would not work for our Boost Team's sync because, you know, it's a much bigger meeting with sometimes up to, you know, 20 to almost 30 people and, like, we can't quite have as much time spent talking about the fun question of the day. So, I definitely think that, you know, it depends your team size, and makeup, and whatnot.
JOËL: Are those questions kind of preset, or do you all get to contribute questions to the list?
STEPHANIE: We brainstormed the questions one retro when we were realizing that we were kind of getting a little bored of the existing question that we had. And we came up with a handful that is plugged into, like, a website, or, like, an app that randomly, you know, picks the question of the day. And so, I think, again, when we get a little bored of the ones that we have in rotation, we'll throw in some curveballs in there.
JOËL: Have you ever considered adding "What's new in your world?" to this rotation?
STEPHANIE: It's funny you mentioned that because it's actually the question that we got a little bit stale on. [laughs]
JOËL: Really?
STEPHANIE: And we needed to inject some new life into, yeah. It's a classic, you know. But I think the variety is nice, especially since we're meeting almost every day. And before we started recording, you and I were just talking about how even sometimes it's tough to think of something that's new in our world [laughs] because we don't always live the most interesting and, you know, new lives. And sometimes, we kind of just have to dig deep to come up with something, and we only meet weekly. [laughs]
JOËL: I can definitely see how doing this daily might be more challenging. I think there's also value in questions that are a little bit more focused. Part of what's fun for this podcast is that "What's new in your world?" is so kind of broad. But maybe for something daily, having something really specific, like, what did you eat for dinner tonight? Means that you aren't just kind of drawing blanks in your mind, like, uh, uh, what is new in my world? What have I done? I don't know; I have a boring life. I don't do anything. Kind of panic mode that you can sometimes get when you hit a meeting.
And so, I do know that when I've been sometimes in situations with people where you have questions like that, I've tended to really appreciate the more targeted ones.
STEPHANIE: Yeah, that's so interesting you mentioned that because I think in social situations, there's usually maybe, like, someone who is really good at asking those, like, specific questions to get the group talking and, like, you know, engaged in a fun conversation, and that specificity helps.
One thing that I was just wondering about is the value of meeting every day in a sync kind of format, and I'm curious if you think that is important to you. If you have been on other teams that don't meet every day, maybe they have, like, a virtual check-in, right? Like, a virtual reminder to share what they're working on as opposed to meeting synchronously.
JOËL: I think I've seen sort of different purposes for sync meetings. Sometimes it's very kind of project-heavy, right? You're talking about the tickets you're working on for today. The reason you're having that is specifically for status updates or because you are blocked, and you want somebody else to help unblock you. So, it's very process-focused. I think that varies team to team, but it can be really helpful.
Even I've been on projects where it's maybe me and one other person, and we'll have kind of an informal just call each other up every morning and say, "Hey, here's what I'm working on today. Here's kind of roughly the strategy I plan to take on it. And we'll go back and forth." And for something like that, it inevitably also somewhat turns into a bit of a social call, so that's planning and social. And I think that can be really strong.
STEPHANIE: Yeah, I like that a lot.
JOËL: That's not necessarily going to be the case for every team, every project, especially with larger teams. And I feel like for something like the Boost Team at thoughtbot, we have a daily sync. We're not all working on the same project. So, I don't want to know about the specific details of the ticket you're working on. I'm more interested in getting just a little bit of face time with the whole of our team to feel a connection.
And, you know, maybe if you've got something cool that you want to share, and that can be a win. It can even be a struggle. And we can all kind of empathize, right? That, like, "Oh, I dropped production database this morning, and I'm kind of freaking out," is a totally fine thing to share. But "I am working on ticket 1, 2, 3, 4 to add some text to a part of the page," that's not particularly useful to me in the kind of sync that we have for the thoughtbot Boost Team.
STEPHANIE: Yeah, absolutely. I think knowing, like, who the audience is of the meeting and, like, how they might be able to support you or be there for you is helpful in making them feel a little more relevant and personal. And I had mentioned that our Boost daily meetings or daily syncs, you know, are a little too big for people to really get into, you know, sharing a fun, personal anecdote, or whatever.
But one thing that I really enjoy is that whoever goes last in giving their update gets to choose the sign-off for everyone. So maybe that's like, okay, we'll just go out on a wave, and we all wave. Or maybe it's, you know, like, making a little heart with your hands. And then there's some folks on the team who go really wild and, you know, come up with something totally unexpected. And I think, you know, that spontaneity is so fun. And we all share it in this collective act of...I'm trying to think of a funny one lately, maybe, like, sinking down into your chair until you disappear from the view [laughs]. That's a good one.
JOËL: Sometimes it's those, like, small social rituals that can be really meaningful.
STEPHANIE: Absolutely. Do you have a favorite sign-off that you have either requested or have done?
JOËL: So, I typically just go for the wave if I'm last because I've not thought about it. But I generally think it's fun to have everybody try to mimic an emoji. So, it might be like, oh, everybody do the, you know, See-No-Evil emoji, or everybody do the party parrot. Those are pretty fun to sign off on.
STEPHANIE: Oh yeah, [inaudible 29:15] pausing is good. I think another one I like is, "Everyone do your best impression of a tree." [laughs]
JOËL: Sometimes, too, it's fun to do something that's relevant to the particular day. If there's something special happening that day, you get something relevant. I've done before, if it's on a Friday, say, "Everybody do your best Rebecca Black impression."
STEPHANIE: Yeah, also excellent.
JOËL: Because, you know, it's Friday.
STEPHANIE: Yeah, like, a little moment of collective celebration for the weekend. On that note, it's a Friday we're recording this episode. Shall we wrap up and look forward to the weekend?
JOËL: [laughter] Fun, fun, fun, fun.
STEPHANIE: Show notes for this episode can be found at bikeshed.fm.
JOËL: This show has been produced and edited by Mandy Moore.
STEPHANIE: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show.
JOËL: If you have any feedback for this or any of our other episodes, you can reach us @_bikeshed, or you can reach me @joelquen on Twitter.
STEPHANIE: Or reach both of us at hosts@bikeshed.fm via email.
JOËL: Thanks so much for listening to The Bike Shed, and we'll see you next week.
ALL: Byeeeeeee!!!!!!
ANNOUNCER: This podcast is brought to you by thoughtbot, your expert strategy, design, development, and product management partner. We bring digital products from idea to success and teach you how because we care. Learn more at thoughtbot.com.Support The Bike Shed