

The Bike Shed
thoughtbot
On The Bike Shed, hosts Joël Quenneville, Sally Hall, and Aji Slater discuss development experiences and challenges at thoughtbot with Ruby, Rails, JavaScript, and whatever else is drawing their attention, admiration, or ire this week.
Episodes
Mentioned books

Oct 18, 2022 • 41min
358: Class Methods
Inspired by a Slack thread, Joël invites fellow thoughtbotter Aji Slater on the show to talk about when you should use class methods and when you should avoid them. Are there particular anti-patterns to look out for? How does this fit in with good object-oriented programming? What about Rails? What is an "alternate constructor"? What about service objects? So many questions, and friends: Aji and Joël deliver answers!
Backbone.js collections
Query object
Rails is a dialect
Meditations on a Class Method
Why Ruby Class Methods Resist Refactoring
Transcript:
JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. And today, I'm joined by fellow thoughtboter Aji Slater.
AJI: Howdy.
JOËL: And together, we're here to share a little bit of what we've learned along the way. So, Aji, what's new in your world?
AJI: Yeah, well, I just joined a new project, so that's kind of the newest thing in my day-to-day work world. I say just joined, but I guess it was about a month ago now. I'm on the Liftoff team at thoughtbot, which is different than the team that you're on. We do more closer to greenfield ideas and things like that. So there's actually not much to speak about there in that project just yet. Rails new is still just over the horizon for us.
So I've been putting a lot of unused brain cycles toward a side project that is sort of a personal knowledge base concept, and that's a whole thing that I could probably host an entire podcast about. So we don't have to go too deep into my theories about that. But suffice it to say I've talked to some other ADHDers like myself who find that that space is not really conducive to the way that we think and have to organize ourselves and our personal knowledge stores. So sort of writing an app that can lend itself to our fast brains a little bit better.
JOËL: Nice. I just recently recorded an episode of this podcast talking a little bit about note-taking approaches and knowledge-base systems. So, yeah, it's a topic that's very much top of mind for me right now.
AJI: Yeah, what else is going on in your world?
JOËL: I'm based in New England in the U.S. East Coast, and it is fall here. I feel like it happened kind of all of a sudden. And the traditional fall thing to do here is to go to an orchard and pick apples. It's a fun activity to do, and so I'm in the middle of planning that. Yeah, it's fun to go out into nature, very artificial space.
AJI: [laughs]
JOËL: But it's a fun thing to do every fall.
AJI: Yeah, we do that here too. There's an orchard up north of us where my wife and I live in Chicago that we try to visit. And Apple Fest in Lincoln Square is this weekend, and we've been really looking forward to that. Try another time at making homemade hard cider this season, I think, and see how that goes.
JOËL: Fun. When you say another time, does that mean there was a previous unsuccessful attempt?
AJI: Yes. Did the sort of naive approach to it, and there is apparently a lot more subtlety to cidermaking than there is home-brew beer. And we got some real strong funk in that cider that did not make it necessarily an enjoyable experience. Like, it worked but wasn't the tastiest.
JOËL: So it got alcoholic. It was just terrible to drink.
AJI: Yeah, I would back that up.
JOËL: So recently, at thoughtbot, we had a conversation among different team members about the use of Ruby class methods, when they make sense, when they are to be avoided. What is their use case? And different people had different opinions. So I'm curious what your take on class methods are. When do you like to use them?
AJI: Yeah, I remember those conversations coming up. I think I might have even started one of those threads because this is something that comes up to me a lot. I'm a long-time listener, first-time caller to The Bike Shed. [laughs] I can remember awaiting new episodes from Sage and Derek to listen to on my way to and from my first dev job. And at one point, Sage had said, "Never put your business logic in something that you can't call .new on."
And being a young, impressionable developer at the time, I took that to heart, and that seems something that just has been baked in and stayed very truthful to me. And I think one of the times that I asked that and got some conversation started was I was trying to figure out why did I feel that, and like, why did they say that? And I think, yeah, I try to avoid them. I like making instances of things. What is your stance on the Class Method, capital C, capital M?
JOËL: I also generally avoid them. I have sort of two main scenarios that I like to use class methods, first is as an alternate constructor. So new is effectively a class method that's built into Ruby's object model. But sometimes, you want variations on your constructor that maybe sets values by default or that construct things with some slightly different inputs, things like that. And so those almost always make sense as class methods. The other thing that I sometimes use a class method for is as an alias for newing up an instance and then immediately calling an instance method on it. So it's just a slightly shorthand way to call some code.
AJI: That's usually been my first line defense of when there's someone who might feel more comfortable doing class methods that sees me making an instance and says, "Well, you don't need an instance, just make a class method here because it'll get too long if you have to .new and then dot this other thing." And so I'll throw in that magic little trick and be like, here you go. You can call it a class method, and you still get all the benefits of your instance. I love that one.
JOËL: Do you feel like that maybe defeats the purpose? In terms of the interface that people are using, if you're calling it a class method, do you lose the benefits of trying to do things at the instance level instead? Or is it more in the implementation that the benefits are not at the caller level?
AJI: I think that's more true that the benefits are at the instance level, and you're getting all of that that goes along with it. And you're not carrying along a lot of what I see as baggage of the class method version, but you're picking up a little bit of that syntactic sugar. And sometimes it's even easier just to conceptualize, especially in the Rails space because we have all of these different class methods like, you know, Find is one I'm sure that we use all the time to call it on a class, and we get back an instance. And so that feels very natural in the Rails world.
JOËL: I think you could make an argument that that is a form of alternate constructor. It's a class method you call to get an instance back.
AJI: Yeah, absolutely.
JOËL: The fact that it makes a background request to the database is an implementation detail.
AJI: For sure. I agree with that. I had a similar need in a recent project where the data was kept on a third-party API. So I treated it the same way as, instead of going out to the database like ActiveRecord does, made a class method that went off to the API and then came back and made the object that was the representation of that idea in our application. So, yeah, I wholeheartedly agree with that.
JOËL: So in Rails, we have the scope keyword, which will run some query to get a collection of records. But another way that they're often implemented is as class methods, and they're more or less interchangeable. How do you feel about that kind of use of class methods on an ActiveRecord object? Does that violate some of the ideas that we've been talking about? Does it sort of fit in?
AJI: I think when reaching for that sort of need, I sort of fall into the camp of making a class method rather than using a scope. It feels a little less like extending some basic Rails functionality or implying that it's part of the inherent framework and makes it a little more like behavior that's been added that's specific to this domain. And I think that distinction comes into my thinking there. I'm sure there are other reasons. What are your thoughts there? Maybe it'll spark an idea for me.
JOËL: For me, I think I also generally prefer to write them as class methods rather than using the scope keyword, even though they're more or less the same thing. What is interesting is that, in a way, they kind of feel like alternate constructors in that they don't give you an instance; they give you back a collection of instances back. So if we bend the rules a little bit...these are not hard and fast rules but the guidelines. If we bend the guidelines a little bit, they kind of fit under the general categories for best uses of class method that we discussed earlier.
AJI: Yeah, I can definitely see that. I tend to think, or at least I think when you had first brought up the term of alternate constructors, my first thought was of one instance; you ask for a thing, and it gives you this thing back. But it's the same sort of idea with that collection because you're not getting just one instance; you're getting many instances. But it's the same kind of idea. You've asked the larger concept of the thing, the class, to give you back individuals of that class. So that totally falls in line with how I think about acceptable uses of these class methods the way that we've been talking about them.
JOËL: Rails is something really interesting where a lot of the logic that pertains to a single item will live at the instance level. And then logic that pertains to a group of items will live at the class level. So you almost have like two categories of operations that you can run that semantically live either at the class or the instance level. Have you ever noticed that separation before?
AJI: I think that separation feels natural to me because I came into programming through Rails. And I might have been colored in my thinking about this by the framework. The way that I conceptualize what a class is being sort of this blueprint or platonic ideal of what an individual might be and sort of describing the potential behaviors of such an individual. Having that kind of larger concept be able to work across multiple instances feels, yeah, it feels sort of natural.
Like, if you were to think about this idea of a chair, then if you went in and modified what a chair is to mean, then any chair that you asked for later on would kind of come with that behavior along with it. Or if you ask for several chairs, they would all sort of have that idea.
JOËL: I think similar to you; I had that outlook on that's almost like a natural structuring of things. And then, years ago, I got into the hot, new JavaScript framework that was Backbone.js. And it actually separates...it has like a model for individual instances, and then a separate kind of model thing for collections. And that kind of blew my mind.
But what was interesting, then, is that you effectively have instance methods that can deal with all things collection-related, any sort of filtering, any sort of transformations. All of those are done, which you have an instance of a collection, basically, that you act on. And I guess if we were trying to translate that into Rails, that's almost like the concept of a query object.
AJI: Hmm, it's sort of an interesting way to think about that. And Backbone, I feel like I did a day of that in bootcamp. But it has been some time, so I'm not sure that I've worked with that pattern specifically. But it does sort of bring up the idea of how much do you want to be in one model class? And do you want it to contain both of these concepts?
If you have a lot of complex logic that is going to be dealing with a collection, rather than putting that in your model, I think I would probably reach for something like a service object that is going to be specifically doing that and sort of more along that Backboney approach maybe like a query object or something like that.
JOËL: Interesting. When you use the term service object, do you mean something that's not a Rails model, just in general? Or are you talking specifically about one of these objects that can respond to call and is... I've heard them sometimes called Command objects or method objects.
AJI: Yeah, that's an overloaded term certainly in the real space, isn't it? Service object, and what does that mean? I think generally, when I say it, I'm meaning just a plain, old Ruby object like something that is doing its one thing. You're going to use it to do its implementation details. They're all kind of hidden behind in private methods and return you something useful that you can then plug into what you were doing or what you need going on in some other place in your app.
So it, to me, doesn't imply any specific implementation of, like, do you have call? Do you use it this way? Do you use it that way? But it's something that's kind of outside of it is either a model, a view, a controller, and it encapsulates some kind of behavior. So whether that, like we're saying, is a filtering or, you know, it's going to wrap that up.
JOËL: I see. So, for you, a query object would be a service object.
AJI: Yeah, I think so. You know, maybe this is one of the reasons why I generally don't like the overuse of the term service object in our space. I don't know if that's a hot take, and I'm going to get emails for this. But --
JOËL: Everybody send your angry tweets @Aji.
AJI: Yeah, do it to @Aji on Twitter because I've been trying to get that three-letter handle for years. No, but if you want to talk to me, I'm @DoodlingDev. But, yeah, certainly, it does feel sometimes like an overloaded term, and I just want to go back to talking about plain, old Ruby objects.
JOËL: So, service object is definitely an overloaded term. It's used for a lot of things. One thing that I've often seen it referring to are objects that respond to call. And just to keep away the confusion, maybe let's call them Command objects for the purposes of this conversation.
AJI: Sounds good.
JOËL: I commonly see them done where the implementation is done with a class method named call. Sometimes it delegates to an instance that also has call. Sometimes it's all implemented as a class method. How do you feel about that pattern?
AJI: I don't mind the idea of a thing that responds to call. It, in a way, sort of implies that the class is sort of named as an action, which I don't like. It has an er name, and that kind of has a class named as a pattern. And that always sort of bugs me a little bit. But what I hope for when I open up one of those sorts of classes or objects is that it's going to delegate to an instance because then you're, again, picking up all of those wonderful benefits of the instance-level programming.
JOËL: You keep mentioning the wonderful benefits of instance-level programming. What are some of those benefits?
AJI: One of the ones that sort of strikes me most visibly or kind of viscerally when I see it is that they're very easy to understand. You can extract methods pretty easily that don't turn into kind of clumsy code of a bunch of different class methods that all have four arguments passed in because they're all operating on the same context. And when you're all operating on the same context, you have really a shared state.
And if you're just passing that shared state around, it just gets super confusing. And you get into the order of your arguments, making a big impact on how you are interacting with these different things. And so I think that's sort of the first thing that comes to mind is just visually noisy, which for me is super hard to get my head around, like, well, how am I supposed to use this thing? Can I extend it?
JOËL: Yeah, I would definitely say that if you have a group of class methods that all take, commonly, it's the first argument, the same piece of data and tries to operate on it, that's probably a code smell that points to the fact that these things want to be an instance that lives around it. This could be a form of primitive obsession if you're passing around, let's say, a hash, all of these, and maybe what you really want is to sort of reify that hash into an object. And then all these class methods that used to operate on the hash can now become instance methods on your richer domain object.
AJI: Yeah. What do you say to the folks that come from maybe a more functional mindset or are kind of picking up on the wave of functional programming that's out there in the ethos that say that you've got a bunch of side effects when you don't have everything that your method is operating on, being passed on or passed in?
JOËL: I think side effect is a broad term. You could refer to it as modifying the internal state of an object. Technically, mutation is a side effect. And then you have things like doing effects out in the outside world, like making an HTTP query, printing to the screen, things like that. I think those are probably two separate concepts. Functional programming is great. I love writing functional code.
When you're writing Ruby, Ruby is primarily an object-oriented language with some functional aspects brought in. In my opinion, it's very, you know, a great combination of the two. I think they've gotten the balance well so that the two paradigms play nicely together rather than competing. But I think it's an object-oriented language first with some functional added in. And so you're not going to be, I mean, I guess you could; there is a way to write Ruby where everything is a lambda or where everything is a class method that is pure and takes in inputs. But that's not the idiomatic way to write Ruby. Generally, you're creating objects that have some state.
That being said, if an object is mutating a lot of global state, that's going to become problematic. With regards to its internal state, though, because it is very much localized and it's private, nobody else gets to see it; in many ways, an object can mutate itself, and that chain stays pretty local.
AJI: Yeah, absolutely. You've tripped onto another one of my favorite rabbit holes of idiomatic code, and, like, what does that mean, and why should we strive for that? But I absolutely agree that when Ruby is written to conform to other paradigms that aren't mostly object-oriented is when it starts to get hard to use. It starts to feel a little off. Maybe it has code smells around it. It's going to give me the heebie-jeebies, whatever that might mean for you or for different developers.
I think we all have our things that are sort of this doesn't feel right. And you kind of dig into it, and you can sort of back that up. And whenever Ruby starts to look like something that isn't lots of little objects sending messages, is when I start to get a little on edge, maybe.
JOËL: It is worth, I think, calling out the fact that Ruby is a very expressive language. And there are effectively many...you could call them dialects of it. You have sort of your pure sort of OO approach. You have what's typically written in Rails, which has some OO things. But Rails is also, in many ways, it's very DSL-heavy and, in some ways, very class method-heavy. So writing Rails is sort of its own twist on Ruby.
And then, some people will try to completely retrofit a functional approach onto Ruby, and that's also a way that some people like to write their code. And some of these, you can't necessarily say they're not valid, but they're not what you'll mostly see in the wild. And they're not necessarily the approach that I would recommend.
AJI: Yeah, that's the blessing, and the curse of both programming in general and such an expressive language like Ruby is that there are many different valid ways to do it. And what are your trade-offs going to be when you make those choices? I think that falls kind of smack dab into that idiomatic conversation.
And it comes up for me, too, as a consultant because I try to tend towards that idiomatic, those common patterns and practices because I'm not going to live with this code forever. I need to hand this off. And the closer it is to what you might see out there in the wild more commonly, the easier it will be for the next Ruby developer to come pick it up and extend it.
JOËL: So you'd mentioned earlier some of the benefits of instance programming. One of the things that I find is maybe a little bit weird when you go heavily into the class method approach is that there is only one instance of the class, and it is globally available.
AJI: Are you talking about a singleton there?
JOËL: Yes. And, in fact, your class is effectively a singleton, potentially with globally mutable state. I hope not, but potentially with all of the gotchas and warnings that that entails. And so, if you think of your user instance, you need a reference to it, and there can be multiple of them, and you can call methods on them. If everything is happening at the class level, there is a single user class in memory shared by anyone who wants to use it. It's globally accessible. You can all call methods on it. Yeah, in many ways, it does act like a singleton.
AJI: And let's not even get into the Ruby chestnut of everything's an object. So it is an instance of a class in and of itself.
JOËL: Yes.
AJI: But, absolutely, it can start to act that way. But the singleton it's enshrined in the Gang of Four book of patterns. Like, so what's wrong about a singleton? I hope you can understand over the airwaves the devil's advocate that I'm playing here. [laughs]
JOËL: Yes. There are little horns that have sprouted on your head right now. I think part of the problem with singletons is that, generally, they are globally accessible. There's the problem of global mutable state again. There was a time, I think, when the OO community went pretty wild with singletons, and people realized that this was not great. And so, over time, a consensus evolved that singletons are a pattern that, while useful, should be used rarely and in moderation.
And a lot of warnings have been shared in the community, like, be careful not to overuse the singleton pattern or don't build your system out of singletons. And maybe that's what feels so weird about a system that's built primarily in terms of class methods for me is that it feels like it's built out of singletons.
AJI: Yeah. When I think of object-oriented programming, I kind of fall back to maybe one of the ideals of it is that it represents the world more accurately or maybe more understandably. And that sort of idea doesn't fit that paradigm, does it? If you're a factory that is making widgets, there's not the one canonical widget that all of your customers are going to be talking to and using. They are going to each have their own individual widgets. And those customers can be thought of like the consumers of your methods, your objects.
JOËL: The idea being the real-world thing you're simulating normally, there are multiple actors of every type rather than a single sort of generic one that stands in for everybody.
AJI: If this singleton is going to be your interface or the way that you interact with each of these things that are conceptually different, like a user or something like that, then differentiating between which user becomes a lot harder to do. It takes a lot more setup and involved process in referring to this user when and that kind of thing and creating the little instances. Then you've got more kind of direct reference to a single concept, a single individual.
JOËL: So what you've described is a very sort of classic OO mindset. You find the data and the behaviors that go together. You try to oftentimes simulate the world, model it in terms of actors that give and receive messages. In many ways, though, I think when you're building a system out of class methods, you're thinking about the world in an almost different paradigm. In many ways, it feels almost procedural. What are the behaviors that need to happen in my app? What are the things that need to be done?
You'd mentioned earlier that oftentimes these classes or the methods on them will end up with E-R; they're all verbs. You have a thing-doer, a thing executor, thing manager. They all do things rather than having domain concepts extracted and pulled out. Would you say that that feels somewhat procedural to you as well?
AJI: Yeah. I think a great way to divide it is the way that you have right there; it's these sorts of mindsets. Do you have collections of things that have behaviors, or do you have collections of behaviors that might refer to things? And where you're approaching the design of a system, either from that behavior side or from that object side, is going to be a different mindset. Procedural being more focused on that kind of behavior and telling it what to do rather than putting... I think this is probably a butchered Sandi Metz example, but putting your roommate who hates cats and a cat that doesn't want its tail stepped on in one room, and eventually, things will happen accordingly.
And those two mindsets are going to end up with very different architectures, very different designs, very different ways of building these applications that we make. And, again, does that come back to...Ruby, potentially to a lesser extent but still in the same camp, is object-oriented language, and it sort of functions best when considered and then constructed in that mindset.
And I often wonder sometimes if language developers and language designers make anti-patterns sort of purposefully awkward to use. Like, if you want to hide a lot of class methods, you can do the class shovels self version of things or have private_class_method littered all the way through your file. And it seems to me like that might be a little bit of a flag that, like, hey, you're working against the system here. You're trying to make it do a thing that it doesn't naturally want to do.
JOËL: Yeah, because you'd mentioned this private_class method thing because, by default, it's hard to get class methods to be private. You have to use a special keyword. You can't just write private in the class and then assume that the methods below it are going to be private because that does not apply to class methods.
AJI: Exactly. And that friction to making an object that has a smaller interface, that kind of hides its implementation, seems as though it's a purposeful way that Ruby itself was designed to maybe nudge us, developers, into a certain way of working or suggesting a certain mindset.
JOËL: There's a classic Code Climate article titled Class Methods Resist Refactoring. And it mentions different ways that when you're relying heavily on class methods, it's harder to do some of the traditional refactors things like just extract method because it is clunkier because you can't have private methods as easily. You can't share state, so you have to thread variables through. I guess, technically, you can share state with things like class variables and class instance variables, but if you do that, you will probably be very sad.
AJI: [laughs] Yeah, you're opening yourself up to a whole world of hurt there, aren't you? And, yeah, you're opening yourself up to a whole world of hurt there with that, aren't you? Sort of sharing data so dangerously around your app.
JOËL: So I'm a big fan of test-driven development. And one of the things that TDD believes in is that test pain should help guide the design of your system and that, generally, things that are easier to test are better designed.
AJI: Yeah.
JOËL: It's often easier to test class methods because they are globally available singletons. I can easily stub a class. Whereas if I need to stub an instance, I need to do some uglier things like stub any instance of or stub the constructor to return a double, or do some other kind of dirty tricks like that. Does that mean that TDD would prefer a class method-based approach to writing code?
AJI: I think that a surface-level reading of that might say that it does. And I think that maybe the first pass on things, if you're thinking about I want to get this thing done that's right in front of me right now and just move forward, might kind of imply that. But if you start to think about or have come back to something that was implemented in that way, anytime that sort of behavior is going to grow or change, then it's going to start to...the number of backflips that you have to do become a lot more complicated and a lot higher when you've got class methods.
Because I find that, yes, you might have to stub out or pass in a created object or something like that. But if you've got a class method, especially if it is calling other class methods inside it, then all of a sudden, you have in your test this setup that looks completely unrelated to anything that you're running and testing, that you have to have all of this insight or knowledge of what those classes are doing just to set up your test framework before you can even run that.
Another thing that is looked to as an axiom when writing tests that can imply this class approach is that you shouldn't change your code just for the test. If you're doing dependency injection or something like that, passing around little objects, then you're making your code more complicated to make your tests look a certain way.
JOËL: That's interesting. So maybe I'm reacting to some test pain by trying to change my tests first. So I'm trying to deal with some collaborators, and it is tricky to do. And so I decide, well, the thing I want to do is I want to reach for stubbing. But then that's hard to do because it's instances. So in order to make already that compromise in my test work better, now I change the code to be nicer for the test to use mostly classes because those are global.
Whereas maybe the correct path to take initially is, say, oh, there isn't test pain here because I'm trying to isolate an object from its collaborators. Maybe we need to pass an object in as an argument rather than hard coding it inside the class.
AJI: Yeah, absolutely.
JOËL: So I guess you follow the test pain, but maybe the problem is that you've already kind of gone down a path that might not be the best before you got to the point where you decided that you needed a class method.
AJI: And I think that idea of following the test pain can be, again, there are only shades of gray; there is no black and white. It can be sort of taken in a lot of different ways. And the way that I think about it is that test pain is also sort of an early warning sign that there's going to be pain if you want to reuse this class or these behaviors somewhere else. And if it was useful somewhere, it's likely it's going to be useful in another place.
And there are many different kinds of tests pain. The testing is a little easier with a class method because you're not stubbing out any instance of. You're just stubbing; really, what's the difference between stubbing out any instance of or stubbing out the class? Is that just a semantic difference? Is that --
JOËL: Because someone on the internet said that stubbing any instance of is bad.
AJI: Ooh, right, the internet. I should have read that one. The thing that you can do with passing around instances or sending messages to instances as you do when you're calling a method is that you can easily swap in a different object if you need to stub it. It's similar to how you can change the implementation under the hood of an object and pass in an object that responds to the same messages and kind of keep moving forward with your duck typing.
If you can go into your tests and pass it sort of an object that's always going to return a thing...because we're not testing what that does; we just need a certain response so that we can move forward with the pathway that is under test. You can do that in so many different ways. You could have FactoryBot, for instance, give you a certain shape of a thing. You can create a tiny, little class right there in your tests that does something specific, that can be easily understood what's going on under the hood here.
And instead of having to potentially stub out or create all of these pathways that need to be followed that are overwriting logic that's happening in different class methods or different places otherwhere in the application, you can just pass in this one simplified thing to keep your tests sort of smaller and easier to wrap your head around all in just one go.
JOËL: I think what I'm getting here is that when you design your code around instances, you're more likely to build it in a modular way where you pass objects to other objects. And when you build your code using class methods, you're more likely to write it in a hard-coded way. Because you have that globally available class, you just hard-code it and then call it directly rather than passing things in. And so things end up more coupled and, therefore, high coupling leads to more test pain.
AJI: Yeah, I think you've really kind of hit on something here that the approach of using class methods is locking that class into kind of a single context or use case. Usually, it is this global thing that is this one way, and that's even kind of backed up by the fact that class methods are load-time logic instead of run-time logic. And it really kind of not only couples but it makes it more brittle and less amenable to kind of reuse.
JOËL: That's a really interesting distinction. I often tend to think of runtime versus load time in terms of composition versus inheritance. Composition, you can combine objects together at runtime and get behaviors built on the fly as the code is executing, whereas inheritance sort of inherently freezes you into a particular combination of behaviors at the time of loading the code. It's something that the programmers set up, and so it is much less flexible.
And that is one of the arguments why the Gang of Four patterns book recommends composition over inheritance in many situations is because of that runtime versus load time dichotomy. And I hadn't made that connection for class methods versus instance methods, but I think there's a parallel there.
AJI: Yeah, absolutely. The composition versus inheritance thing, I think, goes very hand in hand with the conversation that we're having about putting your behavior on a class versus an instance because...and I don't know if this is again yielding my thoughts to 'the internet said' in that composition is preferable to inheritance. But without unpacking that right there, that is certainly something that I strive for as well. And while it might have, much like TDD, some kind of superficial, short-term complexity, it has long-term payoff in that flexibility and that reuse, and that extensibility, and all of those other buzzwords that we developers like to throw around.
JOËL: So you've shared a lot of thoughts on the use of class methods. I think this could branch into so many other aspects of object-oriented design that we haven't looked at or that we could go deeper, things like TDD. We could look into how it works with the solid principles, all sorts of things. But I think the big takeaway for me is that class methods are very useful, but it's easy to use them as our single hammer to every problem being a nail.
And it's good to diversify your toolset. And some tools are specialized; they're good to be used in very specific situations that don't come across very often, and others are used every day. And maybe class methods are the former.
AJI: Absolutely. That hammer-and-nail metaphor was right where I was headed for too. Love it.
JOËL: Well, thank you so much, Aji, for joining the conversation today. Where can people find you online?
AJI: Yeah, anywhere you want to look for me: Instagram, GitHub, Twitter. I'm @DoodlingDev, so just send all your angry emails that way.
JOËL: And with that, let's wrap up.
The show notes for this episode can be found at bikeshed.fm.
This show is produced and edited by Mandy Moore.
If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show.
If you have any feedback, you can reach us at @_bikeshed, or reach me at @joelquen on Twitter, or at hosts@bikeshed.fm via email. Thank you so much for listening to The Bike Shed, and we'll see you next week. Byeeeeee!!!!!!!
ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.Support The Bike Shed

Oct 11, 2022 • 31min
357: Notetaking For Developers
Joël is joined by Amanda Beiner, a Senior Software Engineer at GitHub, who is known for her legendary well-organized notes. They talk about various types of notes: debugging, todos, mental stack, Zetelkasten/evergreen notes, notetaking apps and systems, and visual note-taking and diagramming too!
@amandabeiner
Mermaid.live
Monodraw
Zettlekasten
Evergreen Notes
Notion
Obsidian
Transcript:
JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. And today, I'm joined by Amanda Beiner, a Senior Software Engineer at GitHub.
AMANDA: Hey, Joël. Great to see you.
JOËL: And together, we're here to share a little bit of what we've learned along the way. So, Amanda, what is new in your world?
AMANDA: Well, one thing I'm really excited about is that my team at GitHub is experimenting with how we're going to incorporate learning and sharing what we've learned with each other in new ways, and I'm really excited to see where people take that.
So, one of the things that we're thinking of is that we all get really busy, and we all have exciting projects that we're working on in the day-to-day, and sometimes it can be really hard to pull yourself away from them to do some learning that would be something that will probably help you in the long run. But every time we do do projects like that, people are really excited about it, and people like to collaborate. So we're just trying to figure out how we can make that a more regular thing because it's great for our whole team.
JOËL: I love that. Do you have a project or something that you've been getting into recently to learn?
AMANDA: Yeah. One of the things that I have been working on is that this is the first backend-focused role that I've had in my entire career. So I feel like I just kind of keep pulling back layers on how different forms of magic work. And I'm just trying to get closer to the metal of what is powering our databases. And that's something that I've been really excited to learn some more about.
JOËL: So it's digging into a lot of, like, Postgres and just general database theory.
AMANDA: Yeah. So for me, I've spent a lot of time at the Active Record layer as I have been settling into my role and figuring out what our domain models are that we care about. And I'm trying to get a little bit more into the questions of why did these tables end up looking the way that they do? Why are they normalized or denormalized where they are? And trying to get a better idea of the theory behind those decisions.
JOËL: And this is a new team that you've joined.
AMANDA: This is an existing team that I've joined a year ago now.
JOËL: So it sounds like you're dealing with a somewhat unfamiliar codebase. You're looking at a bunch of existing models and database tables. That can be a lot to process and understand when you first join a team. Do you have an approach that you like to use when you're looking at unknown code for the first time?
AMANDA: Yeah. I usually like to dive right in as much as I can, even if it's with a very small bug fix or something like that, something that allows me to just get my hands dirty from the beginning and poke around what models I'm dealing with, and maybe some of the adjacent ones that I don't need to know about now but might want to come back to later.
JOËL: One thing that I find is really helpful for me are diagramming and note-taking. So if it's something like a database table or ActiveRecord models that I'm not familiar with, if it's more than maybe two or three, which is probably the most I can keep in my head, I have to start drawing some kind of like an entity-relationship diagram or maybe even just a bulleted list somewhere where it's like here are the things and how they connect to each other. Otherwise, I’m like, I don't know, I don't have enough RAM in my brain for that.
AMANDA: That sounds like a really helpful approach. How do you approach creating these diagrams?
JOËL: Occasionally, I will just draw it out by hand with pen and paper. But more recently, I've been using tools like Mermaid.js and specifically the website mermaid.live that allows you to just put in some names and arrows, and it will build out a diagram for you. And that's been really helpful to explore and understand what is going on with different entities that relate to each other.
AMANDA: I've used Mermaid.js recently, and I really enjoyed it as well. I found that writing something that lets me write words or something somewhat like words and takes care of the drawing for me is probably best for everyone involved.
JOËL: Yeah, that's a good point. It's kind of like Markdown, the ability to just write a little bit of text and move on and not worry about the size of boxes or the shape of the arrows or whatever. It helps you to really stay in that flow and keep moving.
AMANDA: I definitely agree. I feel like I can't have been the only person that somehow ended up very deep into the Figma documentation because I didn't quite know how to do what I was supposed to do, and I forgot what I was trying to draw in the first place.
JOËL: Right. It's really easy to put your designer hat on and want to make something like a beautiful diagram when this is really more of a capturing your state of mind. It's a rough note, not something you're necessarily going to publish. So, in addition to visuals, do you find yourself taking a lot of notes when you're exploring code or debugging code?
AMANDA: Yeah. I feel like I tend to jot a lot of things down, maybe class names, maybe some links to PRs or issues, or anywhere that might have context about what I'm looking at and how it got in that way. At this point in the process, it feels my notes usually feel like a bit of a bullet point list that doesn't quite make sense to me yet but maybe will get some shaping later.
JOËL: What kind of things do you tend to record in those notes?
AMANDA: I think one of the things that I'm usually trying to get out of those notes is just a snapshot of what I'm trying to accomplish at the time that I'm creating them. What's the bug that I'm trying to solve, and how did I get into this rabbit hole? So that if it ends up being the wrong one, I can follow my breadcrumbs back out and start a different way.
JOËL: Oh, that is really powerful. I love the imagery you used there of following breadcrumbs. And I feel like that's sometimes something I wish I had when I'm either exploring a particular code path or trying to find a bug. And at some point, I've gone a pretty long path, and I need to back up. And I don't remember exactly where I was or how I got to this point, especially if I've gone down a path, backtracked a little bit, gone down a different path, backtracked, gone further down a third path. And so having breadcrumbs, I think, is a really valuable thing that I wish I did more when I was debugging.
AMANDA: Yeah. And one of the most helpful breadcrumbs that I found is just a list of questions. What was the question that I was trying to answer when I opened this file or looked at this method, and did it help me solve that question or answer that question? And if the answer is no, then I can refer back to what the question was and try to think about what else might help me solve that question.
JOËL: I also love that. It's really easy to get sidetracked by other questions or other ideas when exploring or debugging. And sometimes I find that half hour later, I haven't answered the original question I came here to answer, and I kind of haven't even tried. And so, maybe writing down my questions before I go down a path would help me stay more focused during a debugging session rather than just trying to keep it all in my head.
AMANDA: I very much relate to getting nerd sniped by something that looks interesting but ultimately doesn't solve the original problem that you were trying to.
JOËL: This even happens to me when I'm pair programming. And so we'll say out loud the question we're trying to answer is this; let's open this file. And then you go into it, and you're like, oh, now that is an unusual line of code right there.
AMANDA: [laughs]
JOËL: I wonder why they're doing that. Let me check the git blame on this line. Oh, it's from 2015?
AMANDA: [laughs]
JOËL: I wonder what was happening there. Was that part of a Rails upgrade? And then, at some point, the other person has to interject and be like, "That's all fascinating, but I think the question we're actually trying to answer is..." and we get back on track.
AMANDA: I feel like that's a really good opportunity, maybe for a different kind of note of just interesting curiosities in a given codebase. I find that one of the skills that I'm trying to get better at is, rather than building a repository of information or answers to questions, just building a mental map of where the information I'm trying to find lives so that when someone asks me a question or when I have to solve something I don't necessarily know the answer, but I just know the resource to find that will point me in the direction of that answer.
And I feel like those kinds of explorations are really helpful for building out that mental model, even if it may be at the time seems like an unrelated rabbit hole.
JOËL: So this kind of note is a bit more permanent than a bread crumb style note would be.
AMANDA: Yeah, maybe. And I guess maybe it's less of a note, and it feels kind of like an index.
JOËL: Hmmm.
AMANDA: Like something that's connecting other pieces of information.
JOËL: That's really interesting. It's got me thinking about the fact that note-taking can be very different in different situations and for different purposes. So we've talked a little bit about debugging. I think we've mixed debugging and exploration. Maybe those two are not the same, and you treat notes differently. Actually, do you treat those two as different, or do you have different approaches to note-taking when you're exploring a new codebase versus debugging a particular problem?
AMANDA: I think that those kinds of notes could probably be a little bit different because I think when I'm onboarding onto a new codebase, I'm trying to cast a pretty wide net and give some overall information about what these things do that by the time I'm very deep in debugging, it might be information that I already know very well. So I feel like maybe debugging notes are a little bit more procedural. They are a little bit more I did X, and I did Y, and I did Z, and these were the questions.
And the introductory notes to a new codebase might be more along the lines of this is what this model does, and stuff that will eventually become second nature and might be useful to pass off to someone else who's onboarding but which I might myself not refer back to after a certain amount of time.
JOËL: I see. That's an interesting point because not only might the type of notes you take be different in different scenarios, but even their lifespan could be different. The value of a debugging note, that sort of breadcrumbs, might really only be that useful for a few hours or a couple of days. I can imagine notes you're taking while you're exploring a codebase those might be helpful for a much longer period and, as you said, maybe in passing them on to someone else when they're joining a team.
AMANDA: So that makes me think of whether the debugging notes should be as short-lived as I'm making them sound because I feel like there are times where you know you've debugged something previously, but you didn't keep the notes. Maybe they were just on a scrap of paper, and now they're gone. And I feel like I'd like to do a better job of digesting those notes a little bit better and eventually turning them into something that can be a little bit longer-lived.
JOËL: That's fair. I find that, especially for debugging, I like to capture a lot of what was in my notes in the eventual commit message for the fix. Of course, my random breadcrumbs probably don't make sense in the commit message, but a lot of what I have learned along the way often is helpful.
AMANDA: That's a really good point. I hadn't thought of commit messages as notes, but you're right; they totally are.
JOËL: One thing I've done is I've sort of taken this idea to the extreme. I was debugging some weird database table ActiveRecord model interactions, and the modeling was just a little bit unusual. There were multiple sources of truth in the relationships. And there were enough models that I struggled to really understand what was going on.
And so I drew an entity-relationship diagram. And I felt that that was important to understand for people reviewing the code but also anybody looking back at the commit later on. So I used a tool called Monodraw, which allows you to draw simple diagrams as ASCII art. And so, I have a little ASCII art ERD in my commit message.
AMANDA: That's incredible. I feel like if I were a developer git logging and I saw that commit message, I would be both thrilled and terrified of what exactly I was diving into in the git blame. [laughs]
JOËL: Definitely both, definitely both. But I have referred back maybe a few months later. Like you said, I had to refer back to that commit because a similar bug had cropped up somewhere else. And I knew that that commit had information that I had gathered that would make the debugging experience easier.
AMANDA: I guess the commit message is a really good example of having a note that's very closely tied to its context. Like, it's in the context of like a commit, which is a set of changes at a point in time, and it's really well situated in there. What do you think about the trade-offs of having that as part of a commit message versus something like some other sort of documentation where something like that could live?
JOËL: I guess it depends on how you think you're going to use it in the future. Again, for debugging things, it feels like you don't often need to refer back to them, so I don't think you would want to just dump that on a wiki somewhere. It probably makes sense to have that either in just a collection of debugging notes that you have or that you could then dig into if you needed or in a commit message, something like that. But maybe some of the things that you learned along the way could be pulled out and turned into something that lives somewhere else that's maybe less of a note at that point and more of a publication.
AMANDA: That sounds like a fine line between note and publication.
JOËL: Perhaps it's an artificial line that I'm making.
AMANDA: [laughs]
JOËL: But yeah, I guess the idea is that sometimes I will look at my own debugging notes and try to turn them into something like either a wiki page for a particular codebase or potentially even a blog post on the thoughtbot blog, something that I've been able to synthesize out of the notes there. But now you've kind of gone a few steps beyond the underlying raw notes.
AMANDA: I'm interested in your thoughts on that synthesis of notes into how does something go from a commit message into a blog? What does that process look like for you?
JOËL: I have a personal note-taking system that's loosely inspired by a system called Zettelkasten and also another similar system called evergreen notes. The idea is that when you learn things, you capture small atomic notes, so they are an idea in your note-taking application, and then you connect them. You create links between notes. And the idea is that there's a lot of value in making connections between notes that's almost as much part of the knowledge-creating experience as capturing single notes on their own.
And as you capture a bunch of these little, tiny notes over time and they become very interconnected, then you can start seeing, oh, this note from this one experience, this note from this conference talk, and this note from this book all connect together. And they maybe even make connections I hadn't seen, or I hadn't thought of individually in those moments. But now I see that they all kind of come together with a theme. And I might then combine those together to make a blog post or to use as the foundation for a conference talk.
AMANDA: That's really interesting. I like the concept of being able to capture bits of information at the time that they felt relevant without having to have an entire thesis in this note. Or that idea doesn't have to be fully fleshed out; it can become fleshed out later when you connect the dots.
JOËL: That's a really powerful concept. One of the big ideas that I picked up through this was that there are always byproducts of knowledge creation. So if I'm writing a blog post, there are always some things that I cut that didn't make it into the blog post because I'm trying to keep it focused. But those are still things that I learned, things that are valuable, that could be used for something else.
And so anytime I'm writing a blog post, preparing for a conference talk, learning some things in a debugging session by reading a book, there are always some things that I don't use necessarily immediately. But I can capture those little chunks, and eventually, I have enough of them that I can combine them together to make some kind of other work.
AMANDA: I'm really curious about your process of creating those notes. If you're reading a blog post, say, to learn a new topic and you're taking notes on that, how do you go from this concept that you're learning in the blog post to these really focused notes that can be combined in other ways?
JOËL: So the Zettelkasten approach suggests that you have two forms of notes, one it calls literature notes which are just sort of ideas you jot down as you are reading some work. You're reading a book or a blog post or watching a talk, and then, later on, you go and turn those into those atomic-separated, linked notes together, what Zettelkasten calls permanent notes. And so I'll often do that is just focus on the work itself and jot down some notes and then convert those later on into these smaller atomic chunks.
AMANDA: That concept of taking a larger theme and then actually spending the energy to distill that into a different kind of artifact that might be helpful later on is really interesting. And I don't do Zettelkasten note-taking, but I've also found that to be useful in other contexts as well.
JOËL: One thing that I sort of hold myself to is when I am writing those atomic notes is, I don't write them as bullet points. They're always written in prose and complete sentences. The title is usually a sort of thesis statement, a thing that I think is true or at least a thing that posits that could be true, and then a short paragraph expanding on that idea which I think helps cement a lot of information in my mind but also helps to give me little chunks of things that I can more or less copy-paste into an article and already have almost a rough draft of something I want to say.
Do you find that when you synthesize ideas into notes that you do something similar, or do you stick mostly to bullet points?
AMANDA: I think I might do a mixture of the two. I think procedurally, I use bullet points a lot, but I think those bullet points tend to be full sentences or several sentences together. I've definitely run up against some of the drawbacks of terseness, where they're less helpful when you refer back to it later. But I do like the visual cues that come with things like bullet points, or numbered lists, or even emoji and note-taking to be a visual cue of what I was thinking of or where I can find this later on.
JOËL: I love emoji; emoji is great.
AMANDA: I guess actually I've started using emoji as bullet points. That's something that I've found even to be helpful just with remembering or with grouping things thematically in my mind. And when I'm going back through my notes, I find it easier to find the information that I was looking for because it had a list, or an emoji, or an image, or something like that.
JOËL: Yeah, that makes it really easy to scan and pick out the things that you're looking for. It's almost like adding metadata to your notes.
AMANDA: Totally.
JOËL: That's a great tip. I should do that.
AMANDA: You can definitely run into the Figma problem of you then spend so much time finding the right emoji to be the bullet point that you forgot what you were doing, [laughs] but that's a problem for a different day.
JOËL: So this sort of Zettelkasten evergreen notes approach is a system that I use specifically to help me capture long-term thoughts about software that could eventually turn into content. So this is very much not a debugging note. It's not an exploratory note. It has a very particular purpose, which is why I write it in this particular way.
I'm curious; I know you have a lot of different systems that you use for your notes, Amanda. Is there one that you'd like to share with the audience? Maybe tell us a little bit about what the system is and why it's a good fit for the type of scenario that you'd like to use it in.
AMANDA: Sure. One situation that I found myself in recently is I have started taking classes on things that I'm interested in, development-related and non-development-related. And that's a formal structure that requires some note-taking that I haven't really done since I was in school. And the tools were very different back then as to what we had available to us for note-taking. It was basically Microsoft Word or bust.
So I have found myself having to develop a new note system for that kind of content delivery method, basically of watching a video and taking notes and having something that then makes sense outside of the context of sitting down and watching a video. So that has been a little bit of a process journey that I've been on the last couple of months.
JOËL: And what does your note-taking system look like?
AMANDA: So it's been a mix of things, actually. I started out just kind of brain-dumping as I went along with the instructor talking trying to type and keep up. And I found that very not scannable to look back on. I was looking for some more visual cues, and I didn't really have time to insert those visual cues as I was trying to keep up with a lecture essentially.
I then transitioned back to old school pen and paper, like, got myself a notebook and started writing in it. And obviously, that has some benefits of the free-formness, like, I'm not constrained by the offerings of any specific tool. But the trade-off for that is always that you have different notebooks for everything. And it's like, where's my X class notebook?
And so I've been trying to bring those two methods together into something that makes a little bit more sense for me and also bring in some of that synthesis process that you were talking about with your note-taking method of doing the full literature notes and then synthesizing them down into something a little bit more well-scoped for the particular piece of information.
JOËL: So you have like a two-step process then.
AMANDA: It did end up being a two-step process because one of the things that I found was the grouping of ideas that make sense when you're first learning a concept and the grouping of ideas that make sense when I'm revisiting that concept, later on, aren't necessarily the same. And so, keeping it in the original context doesn't necessarily help me recall the information when I'm referring back to my notes.
JOËL: That's really interesting. When you're writing it, it's going to be different than when you're reading it.
So we've been talking a lot about the purpose of different notes along the way, and you mentioned the word recall here. Do you use these notes mostly as a way to recall things that you would look back at them and try to remember, or are they more of a way to digest the material as you're going through it?
AMANDA: I think at the time that I'm writing them, they definitely served the purpose of helping me digest the information. But at some point, I probably want to be able to look back at them and remember the things that I learned and see if maybe they have new salience now that I have sat on them for a little bit.
JOËL: Hmmm, that's good. So it's valuable for both in different contexts.
AMANDA: Yeah, definitely. And one of the more surprising things that I've learned through that process has been that when I'm learning something, I really like a chronological kind of step-by-step through that process and building blocks of complexity that basically go one on top of the other. But then, once I've kind of made it to the end when I look back on it, I look back on those notes, and they're usually pretty thorough. They probably have a lot of details that aren't going to be top-level priority at the end.
But I didn't really have that concept of priority when I was first learning it. I was kind of grasping onto each bit of information, saying, "I'm going to scroll this away in case I need it later." And then when you get a better understanding of the full picture, you realize, okay, I'm glad that I know that, but it's not necessarily something that I'd want to look back on. So I really like having systems that then allow me to regroup that information once I have built out a fuller picture of what it is I'm trying to learn.
JOËL: Interesting. So the sort of digesting step that happens afterwards or the synthesis step, a lot of the value that you're adding there is by putting structure on a lot of the information you captured.
AMANDA: Yeah, I think putting structure and changing the structure, and not being afraid to change that structure to fit my new understanding in how I see this concept now instead of just how this concept was explained to me.
JOËL: So you mentioned that you'd initially used notebooks and paper and that that felt a little bit constraining in terms of organization. Is there any kind of software or apps that you like to use to organize your notes, and how do they fit in with your approach to note-taking?
AMANDA: I've been using Notion for the last few years. I found that that application works well with my visual preferences for note-taking. I think there's a lot of opportunity for visual cues that help me recall things, such as emoji and bullet points. And I like that I can do all of that by writing Markdown without then also having to read Markdown.
JOËL: Yeah, I definitely agree that a little visual change there where you can actually see the rendered Markdown is a nice quality-of-life improvement.
AMANDA: Absolutely. And I also think that the way that it turns Markdown into blocks that then you can rearrange has served me really well for that synthesis process of maybe this bullet point makes sense, and I want to keep it as is. But I want to rearrange it into these new themes that I'm seeing as I'm reviewing these things that I've learned.
JOËL: That's fascinating. So it has some really good tools for evolving your notes and reorganizing them, it sounds like.
AMANDA: I like that I can group my notes by concept, and notes can be subsets or sub-notes of other notes. And you can kind of move the individual notes in between those blocks pretty easily, which helps me rearrange things when I see different themes evolving.
JOËL: I've heard really good things about Notion, but I've not tried it myself. My app of choice so far has been Obsidian, which I really appreciate its focus on linking between notes. It doesn't have this concept of blocks where you can embed parts of notes as notes into other notes and things like that. But that has been okay for me because I keep my notes very small and atomic. But the focus on hyperlinking between notes has been really useful for me because, in my approach, it's all about the connections.
AMANDA: So, what does that process look like when you are referring back to all of these notes that are hyperlinked together?
JOËL: That's actually really important because the recall aspect is a big part of how you would use a note-taking system. For me, it's sort of like walking the graph. So I'll use search, or maybe I know a note that's in the general theme of what I care about, and then I'll just follow the links to other related articles or notes that talk about things that are related to it. And I might walk that graph three, four steps out in a few different directions. It's kind of like surfing Wikipedia. You find some entry point, and then you just follow the links until you have the material that you're interested in.
AMANDA: It sounds like creating a Wikipedia wormhole of your own.
JOËL: It kind of is. I guess, in a way, it's kind of like a little mini personal wiki where the articles are very, very condensed because I have that limitation that everything must be atomic.
Wow. So this has been a really fascinating conversation. I feel like one of the big takeaways that I have is that types of notes matter. Note-taking can take very different forms in different contexts. And the way you organize them would be vastly different; how long you care about them is also going to be different.
So going into a particular situation, knowing what sort of situation is this that I'm using notes and what is their purpose is going to be really helpful to think in terms of how I want to do my note-keeping. Whereas I think previously, I probably was just like, yeah, notes. You open a document, and you put in some bullet points.
AMANDA: I am definitely guilty of doing that as well. And I like the idea of having a purpose for your notes. You mentioned your purpose was ultimately to build a map that would produce content. And I really like how you have found a system that works really well for that purpose. And I'm going to keep thinking about how to be more intentional in what is the purpose of the notes that I'm taking in the future.
JOËL: Well, thank you so much for joining the conversation today. Where can people find you on the web?
AMANDA: Thanks so much for having me, Joël. You can find me @amandabeiner on Twitter.
JOËL: And we'll link to that in the show notes. And with that, let's wrap up.
The show notes for this episode can be found at bikeshed.fm.
This show is produced and edited by Mandy Moore.
If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show.
If you have any feedback, you can reach us at @_bikeshed, or reach me at @joelquen on Twitter, or at hosts@bikeshed.fm via email. Thank you so much for listening to The Bike Shed, and we'll see you next week. Byeeeeeeee!!!!!!!
ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.Support The Bike Shed

Sep 27, 2022 • 39min
356: The Value of Specialized Vocabulary
Guest and fellow thoughtbotter Stephanie Minn and Joël chat about how the idea of specialized vocabulary came up during a discussion of the Ruby Science book. We have all these names for code smells and refactors. Before knowing these names, we often have a vague sense of the ideas but having a name makes them more real. They also give us ways to talk precisely about what we mean. However, there is a downside since not everyone is familiar with the jargon.
This episode is brought to you by Airbrake. Visit Frictionless error monitoring and performance insight for your app stack.
Stephanie's previous talk
Non Violent Communication
RubyConfMini
Ruby Science book
Connascence as a vocabulary to discuss coupling
Wired series "5 levels of teaching"
Transcript:
JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. And today, I'm joined with fellow thoughtboter Stephanie Minn.
STEPHANIE: Hey, Joël.
JOËL: And together, we're here to share a little bit of what we've learned along the way. Stephanie, what is new in your world?
STEPHANIE: Thanks for asking. I am on a new project I just started a few weeks ago, and I'm feeling the new project vibes, I think, kind of scoping out what's going on with the client with the work that they're doing. Trying to make a good impression. I think lately I've been in that mode of where can I find some work to do even when I'm just getting on boarded and learning the domain, trying to make those README updates in the areas that are a bit outdated, and yeah, just kind of along for the ride.
One thing that has been surprising already is that in my second week, the project pivoted into a different direction than what I was expecting. So that has been kind of exciting and also pretty interesting to see sometimes this stuff happens. I was brought on thinking that we were working on rebuilding the front end in React and TypeScript, pulling out pieces of their 15-year-old Rails monolith. So that was kind of one area that they decided to start with.
But recently, they actually decided to pivot to just revamping the look of the existing pages in the Rails app using the same templates and forms. So it's kind of shifted from more greenfield-esque work to figuring out what the heck's going on in this legacy codebase and making it a little bit more modern-looking and cleaning out the cobwebs, I suppose as we find them.
JOËL: As a consultant, how do you deal with that kind of dramatic shift in expectations?
STEPHANIE: I think it's tough because I necessarily wasn't in those conversations, and so I have to come at it with the understanding that they have a deep knowledge of the business and things that are going on behind the scenes that I don't, and I am coming in kind of with a fresh set of eyes. And it definitely raises some questions for me, right? Like, why now? What were the trade-offs that were made in the decisions?
And I hope that as a consultant, I can poke and prod a little bit to help them with the transition and also figuring out its impact on the rest of the team in a way maybe someone who is more familiar with the situation and more tied to the politics of the org might not have that perspective.
JOËL: I have a lot of questions here. But actually, I'm thinking that onboarding as a topic would probably make a good standalone episode. So maybe we'll have to bring you back for a future episode to talk about how to onboard well and how to deal with surprises.
STEPHANIE: Yeah, I think that's a great idea. What about you, Joël? What's going on in your world?
JOËL: I'm doing an integration with a third-party gem, and I am really struggling. And I've gotten to the point where I'm reading through the source of the gem to try to figure out some weird errors, some things that come up that are not documented. I think that's a really valuable skill. Ideally, you're not having to bring it out too often, but when you do, being able to drop into the code can really help unblock you or at least make some amount of progress.
STEPHANIE: Are you having to dig into the gem's code because you weren't able to find what you needed from the documentation?
JOËL: That's correct. I'm getting some cryptic errors where the gem is crashing, and I'm finding some lines in my logs that point back to the gem. And now I'm trying to reconstruct what is happening. Why is it not behaving the way it should be based on the documentation that I read?
STEPHANIE: Oh, that's tough. Getting into gem code is uncharted territory.
JOËL: It's nice when you're working with an open-source gem because the source is there, and you can just follow the stack trace and go through the code. Sometimes it's long and tedious, but it generally gives you results. It definitely is intimidating.
STEPHANIE: Yeah. When you're facing this kind of problem where you have no idea where the light at the end of the tunnel might be, how long do you spend with it? At what point do you take away with what you've learned and try to figure out a different approach?
JOËL: That's a good observation because digging through the source of a gem can definitely be a time sink. I think how much time I want to budget depends on a variety of other factors. How big of a problem is this? If I can't figure it out through reading the source, do I have alternate approaches to debug the problem, such as asking for help, opening an issue, reaching out to somebody else who's used it, complaining about it on The Bike Shed and hoping someone responds with an answer?
There are other options that I can do that might leave me blocked but maybe eventually give me results. The advantage with reading the source is that you're at least feeling like you're making progress.
STEPHANIE: Nice. Well, I wish you luck on that journey. [laughs] It sounds pretty tough. I'm sure that you'll get to one of those solutions and figure out how to get unblocked.
JOËL: I hope so. I'm pursuing a few strategies in tandem. So I've asked for help, but I'm also reading the source code. And between the two of those, I hope I'll get to a good solution.
So, Stephanie, last time you were on the show, you talked about your experience creating talk proposals for RubyConf. Have you heard back from them since then?
STEPHANIE: I have. I will be speaking at RubyConf Mini this year. And I'm really excited because this will be my first IRL conference talk. So last time, I recorded my talk for RubyConf, and this time I will be up on a stage in front of real people.
JOËL: That's really exciting. Congratulations.
STEPHANIE: Thanks.
JOËL: What is the topic of your talk?
STEPHANIE: I will be talking about pair programming and specifically pair programming through the lens of a framework called Nonviolent Communication, which is a framework I learned about through a friend who recommended the canonical book on it. And it's a self-help book, to be totally frank, but I found it so illuminating. It really changed how I communicated in my relationships in my personal life.
And the more time I spent with it, the more I realized that it would be a great application in pair programming because it's so collaborative and intimate. I've experienced the highs and lows of pair programming. You can feel so good when you are super connected with your pair. You make a lot of progress. You meet whatever professional goals that you might be meeting, and you have someone along for the ride the whole time. It can be just so rewarding.
But it can also be really challenging when you are having more of those interpersonal conflicts, and navigating that can be tough. And so I'm really excited to share this style of communication that might help others who want to take their pair programming to the next level and get the most out of that experience no matter who they're pairing with.
JOËL: I'm excited to hear this talk because pair programming has always been an important part of what we do at thoughtbot. And I think now that we're remote, we do a lot of remote pair programming. And the interpersonal interactions are a little bit different there than when you're physically in a room with each other, or you have to maybe pay a little bit more attention to them. I'm really excited to hear that. I think that's going to be really useful, not just for me but for a lot of the audience who are there.
STEPHANIE: Thanks. Joël, you have a talk accepted at RubyConf Mini too.
JOËL: Yes, I also had a talk accepted titled Teaching Ruby to Count. And it's going to be all about series, enumerators, enumerables, and ranges in Ruby and the cool things that you can do with them. So I'm really excited to share about that. I've done some deep dives on these topics, and I'm excited to share that with the broader Ruby community.
STEPHANIE: Nice. I'm really excited to hear more about it.
JOËL: Did you submit more than one proposal this year?
STEPHANIE: This year, I didn't. But I would love to get to a point where I have a lot of content on the backburner and can pull it out when CFP season rolls around to just have some more options. Yeah, I have all these ideas in my head. I think we talked about how we come up with content in our last episode. But yeah, having a content bank sounds really nice for the future, so maybe when that season rolls around, it is a lot easier to get the ball rolling on submitting. What about you? Did you submit more than one?
JOËL: I submitted two, but this is the one I was most excited about. I think the other idea was maybe a little bit more polished, but this one was a newer one I came up with towards the end of the CFP period. And I was like, ooh, I'm excited about this. I've just done a deep dive on enumerators, and I think there are some cool things to share with the community. And so that's what I'm excited to share about, and maybe that came through the proposal because that is what the committee picked. So I'm super happy to be talking about that.
STEPHANIE: Nice. Yeah, I was just thinking the same, that your excitement about it was probably palpable to the committee.
JOËL: For any of our viewers who are interested in coming to watch the talks by Stephanie and myself and plenty of other gifted speakers, this will be at RubyConf Mini in Providence, Rhode Island, from November 15th to 17th. And if you can't make it in person, the videos will be published online early in 2023. And we'll definitely share the links to that when they come out.
So as we mentioned in your last episode, thoughtbot has a book club where we've been discussing the book Ruby Science, which goes through a lot of code smells and talks about some various refactoring patterns that can be used to fix them. Most recently, we looked at a code smell that has a very evocative name; it's called shotgun surgery.
STEPHANIE: Yeah, it's a very visceral name for sure. I think that is what prompted this next topic that we're about to discuss because someone in the book club, another thoughtboter, mentioned that they were learning this term for the first time. But it made a lot of sense to them because they had experienced shotgun surgery and didn't have the term for it previously. Joël, do you mind giving the listeners a recap of what shotgun surgery is?
JOËL: So shotgun surgery is when in order to make a change to a codebase, you have to make a bunch of little changes in a lot of different files, a lot of different locations. And that means that all of these little pieces are weirdly coupled to each other in a way that to make one change, you have to make a bunch of little changes in a lot of places. And that results in a very high churn diff, and that's a common symptom of this problem.
STEPHANIE: Nice. Thanks for explaining.
MID-ROLL AD:
Debugging errors can be a developer’s worst nightmare...but it doesn’t have to be. Airbrake is an award-winning error monitoring, performance, and deployment tracking tool created by developers for developers that can actually help cut your debugging time in half.
So why do developers love Airbrake? It has all of the information that web developers need to monitor their application - including error management, performance insights, and deploy tracking!
Airbrake’s debugging tool catches all of your project errors, intelligently groups them, and points you to the issue in the code so you can quickly fix the bug before customers are impacted.
In addition to stellar error monitoring, Airbrake’s lightweight APM helps developers to track the performance and availability of their application through metrics like HTTP requests, response times, error occurrences, and user satisfaction.
Finally, Airbrake Deploy Tracking helps developers track trends, fix bad deploys, and improve code quality.
Since 2008, Airbrake has been a staple in the Ruby community and has grown to cover all major programming languages. Airbrake seamlessly integrates with your favorite apps to include modern features like single sign-on and SDK-based installation. From testing to production, Airbrake notifiers have your back.
Your time is valuable, so why waste it combing through logs, waiting for user reports, or retrofitting other tools to monitor your application? You literally have nothing to lose. Head on over to airbrake.io/try/bikeshed to create your FREE developer account today!
STEPHANIE: I think I came away from that conversation thinking about the idea of learning new terms, especially technical ones, and the power that learning those terms can give you as a developer, especially when you're communicating with other people on your team.
JOËL: So you mentioned the value in communication there. Some terms have a very precise meaning, and so that allows you to communicate a very specific idea. How do you balance having some jargon and some terminology that allows you to speak very precisely versus having to learn all the terms? Because the more narrow the term is, the more terms you need to talk about all the different things.
STEPHANIE: That's a great question. I don't know if I have a great answer because I think I'm still on my journey. I have always noticed when developers I work with have that really precise, articulate technical vocabulary, probably because I don't. I am constantly referring to functions or classes as things, like, that thingy over there talks to this thing over here, and then does something. [laughs]
And I think it's because I maybe didn't always have that exposure to very precise technical vocabulary. And so I had an understanding of how things worked in my head, but I couldn't necessarily map that to words. And I'm also from California, so, I don't know, maybe some of that is showing through a little bit. [laughs]
But I've been trying to incorporate more technical terms when I speak and also in written form, too, such as in code review, because I want to be able to communicate more clearly my intentions and leave less room for ambiguity. Sometimes I've noticed when you do speak more casually about code, turns out other people can interpret it in different ways. And if you are using, like you said, that narrower technical term for it, that leaves less room for misunderstanding.
But in the same vein, I think a lot of people are like me, where they might not know the technical terms for things. And when you start using a lot of jargon like that, it can be a bit exclusive to folks earlier in their career, especially since software as an industry we have folks from all different backgrounds. We don't necessarily have the expectation of assured formal training. We want to be inclusive of people who came to this career from different places and make sure that we are speaking the same language. And so it's been top of mind for me thinking about how we can balance those two things. I don't know, what do you think?
JOËL: I want to speak to some of the value of precision first because I think there are a few different points. We have the value of precision, then we have the difficulty of learning vocabulary, and how are we inclusive of everyone. But on the topic of precision, I don't know if you saw not too long ago, another fellow thoughtboter, Matheus Sales, published an article on the thoughtbot blog about the concept of connascence. And he introduces this as a new set of vocabulary, not vocabulary that he's created but a vocabulary that is out there that not that many developers are aware of for different ways to talk about coupling.
So it's easy in a pull request to just say, "Oh, well, that thing looks coupled. How about this other way?" And then I respond, "Well, that's also coupled in a different way." And then we just go back and forth like, "Well, mine is more coupled than yours is," or whatever. And connascence provides a more precise, narrow vocabulary to talk about the different ways that things are coupled and which ones are more coupled than others. And so it allows us to break out of maybe those unproductive discussions because now we can talk about things in a more granular way.
STEPHANIE: Yeah, I loved that blog post. It was really exciting for me to pick up a new term to describe something that I had experienced, or seen in codebases, or felt the pain of, and be able to describe it more accurately. I'm curious, Joël, if you were to use that term next time, how would you make sure that folks also have the same level of familiarity with it?
JOËL: I think on a pull request, I would link to Matheus' article depending on...I might give a little bit of context in a comment. So I might say something like, "This area here is coupled. Here's a suggested refactor. It's also coupled but in a different way. It's because we've moved up this hierarchy of connascence from, you know, connascence of names to some other form" (I don't have them all memorized.) and then link to the article. And hopefully, that becomes the start of a productive discussion.
But yeah, having the resources you can link to people is great. And that's one of the nice things about text communication on a pull request is that you can just link to external resources that people can find helpful.
STEPHANIE: To continue talking about the value of precision and specialized vocabulary, Joël, I think you are a very articulate communicator. And I'm curious from your perspective if you have always been this way, if you've always wanted to collect technical terms to describe exactly what you want to convey, or if this was a bit of a journey for you to get to this level of clear communication in your technical speaking and writing.
JOËL: It's definitely been a journey. I think there are sort of two components to this; one is being able to communicate clearly to others; make sure that they understand what you're talking about. So for that, it's really important to be able to put yourself in somebody else's shoes.
So when I'm building a conference talk or writing up a blog post, I will try to read it or go through my slide deck and try to pretend that I am the audience. And then I ask myself the questions: where do I get confused? Where am I going to have questions? Maybe even where am I going to roll my eyes a little bit and be like, eh, I didn't agree with that leap of logic there; where are you going? And then shift back in author mode and say, how can I address these? How can I make my content speak to you in an area where maybe you disagreed, or you were confused?
So I kind of jump between moving from the audience seat to back to the author and try to make that material as much as possible resonate with those people.
STEPHANIE: Do you do that in more real-time communication, such as in meetings or in pairing?
JOËL: I think that's a little bit harder to do. And then it's maybe a little bit more of asking directly, either pausing to let people interject, or you can ask the question directly and say, "Are you familiar with this term?" That can also sometimes be tricky to manage because you don't want to make it sound like you think they don't know anything.
But you can also make it sound really natural in a conversation where you're like, "Oh, we're going to do this thing with a strategy pattern. Have you seen a strategy pattern before? Are you familiar with this? Great, let's keep moving." And if not, maybe it's like, "Hey, let's take a few minutes to talk about what the strategy pattern means."
STEPHANIE: I think you are really great at asking the audience about their level of familiarity with the content, especially in book club. I have definitely experienced just as a developer pairing, or in meetings, or whatnot times when people don't pause and ask. And usually, I have to muster up the courage to interrupt and ask, "Hey, what is X, Y, and Z?" And that is tough sometimes.
I am certainly comfortable with it in a space where there is trust developed in terms of I don't feel worried that people might question my level of familiarity or experience. And I can very enthusiastically say, "Hey, I don't know what this means. Could you please explain it?" But sometimes it can be a little tough when you might not have that relationship with someone, or you haven't talked about it, talked about assumptions about your knowledge or experience level upfront.
And so I have found that to be a really good way to build that trust to make sure that we aren't excluding folks is to just talk about some of that stuff, even before we start pairing or before a meeting. And that can really help with some of those miscommunications that might come down later in the process.
JOËL: It's interesting that you bring up miscommunication because I think sometimes, even though certain jargon can be very precise, sometimes people will not use it to mean exactly what its dictionary definition is. And so sometimes two people are using the same term, and you're not meaning quite the same thing.
And so sometimes I'll be pairing with someone, and I'll have to sort of pause and say, "Hey, wait a minute, you're using the term adapter in a certain way that seems to be a little bit different than the way I'm using it. Can you maybe tell me what your personal definition is? And I'll tell you mine, and we can reconcile those two together."
Sometimes that can also feel like a situation where maybe I'm hazy on the topic. Like, I have a vague sense of it, and maybe it does or does not align with the way the other person is using it. And so that's an opportunity for me to ask them to define the term for me without completely having to say, "I have no idea what this term is. Please, oh, great sage, explain the meaning."
STEPHANIE: Are there times that you feel more or less comfortable doing that kind of reset?
JOËL: I think sometimes the fear is in breaking flow. And so you're doing a thing, and then somebody is trying to explain something, and you don't want to break out of that. Or you're trying to explain something, and you have to decide, is it worth making sure to explain a term, or do you keep moving? So I think that is a big concern.
And there is just the interpersonal concern of if there is less trust, do I want to put myself out there? Does somebody else maybe not feel comfortable you asked them to explain a term? Maybe they're using it wrong. It's not always good in a pairing situation to just come up and say, "Hey, that's not technically the adapter pattern; you're wrong. Let me pull out The Gang of Four book. You see on page 54..." that's not productive.
STEPHANIE: Yeah, for sure.
JOËL: So a lot of it, I think...and maybe this ties into your topic of communication while pairing. But ideally, you're working constructively with a person. And so debating definitions is not generally productive but asking someone, "What do you mean when you say this?" I find is a very helpful way to lead into that type of conversation.
STEPHANIE: Yeah, that's a great strategy because you're coming from a place of curiosity rather than a place of this is my definition, and it's the right definition, and so, therefore, you are wrong. [laughs]
JOËL: It's interesting the place that jargon occupies in our imagination of expertise. If you've ever seen any movie where they're trying to show that somebody is technically competent, they usually demonstrate that a person is competent by having them just spout out a long chain of jargon, and that makes them sound smart. But I think to a certain extent; maybe we believe it in the industry as well. If somebody can use a lot of terms and talk about a system using this very specific jargon, we tend to think that they're smart or at least look up to them a little bit.
STEPHANIE: Yeah, which I think isn't always the best assumption because I've certainly worked with folks who did throw out a lot of jargon but weren't necessarily, like you were saying, using it the way that I understood it, and that made communicating with them challenging.
I also think what true expertise really is is having the knowledge that when you use a jargony term that not everyone might be familiar with it, having the awareness to pause and ask someone how they're doing with the vocabulary and be able to tailor how you explain that term to that other person. I think that demonstrates a really deep level of understanding that doesn't get enough credit.
JOËL: I 100% agree. Jargon, vocabulary, it's a means to an end, not an end in and of itself. So the goal is to communicate clearly to others and maybe to help yourself in your own learning. And if you're not accomplishing those goals, then what's the point? I guess maybe there is another personal goal which is to sound smart, but that's not really a good goal, [laughs] especially not when the way you do that is by confusing everybody else in the room because they don't understand you, to make you try to feel smarter than them. Like, that's bad communication.
STEPHANIE: Yeah, for sure. I've definitely experienced listening to someone explain something and have to really think very hard about every single word that they're saying because they were using terms that are just less common. And so, in my brain, I had to map them to things that made sense to me, and things that I was familiar with that were the same concepts.
Like, I was experienced enough to have that shared understanding, but just the words that they used required another layer of brain work. Maybe we could have found a happy medium between them communicating the way that they expressed themselves the best with my ability to understand easily and quickly so that we could get on the same page.
JOËL: So you mentioned that there are sometimes situations where you're aware of a particular concept, but maybe you're just not aware that the term that somebody else is using maps to this concept you already understand. And I know that for me, oftentimes, being able to give a name to something that I understand is an incredibly powerful thing.
Even though I already know the idea of passing objects to another object in this particular configuration, or of wrapping things in some way or whatever the thing that I'm trying to do, all of a sudden, instead of it being a more nebulous concept in my head or a list of 10 steps or something like that, now I have one thing I can just point to and say it is this.
So that's been really helpful for me in my learning to be able to take a label and put it on something that I already know. And somehow, it cements the idea in my head and also then allows me to build on it to the next things that I want to learn.
STEPHANIE: Yeah, absolutely. It's really exciting when you're able to have that light-bulb moment when you have that precise term, or you learn that precise term for something that you have been wrestling with or experiencing for a while now.
I was just reminded of reading documentation. I have a very vivid memory of the first time I read; I don't know, even the Rails official docs, all of these terms that I didn't understand at the time. But then once I started digging into it, exploring, and just doing the work, when I revisited those docs, I could understand them a lot more comprehensively because I had experience with the things (There I am using things again.) [laughs] and seeing the terms for them and that helping solidify my understanding.
JOËL: I'm curious, in your personal learning, do you find it easier to encounter a term first and then learn what it means, or do the reverse, learn the concept first and then cap it off by being able to give it a name?
STEPHANIE: That's a good question. I think the latter because I've certainly spent a lot of time Googling terms and then reading whatever first search results came up and being like, okay, I think I got it, and then Googling the same term like two weeks later because I didn't really get it the first time. But whenever I come across a term for a concept I already am familiar with, it is like, oh yes, uh-huh! That really ends up sticking with me.
Matheus Sales' blog post that you mentioned earlier is a really great example of that term really standing out to me because I didn't know it at the time, but I suppose was seeking out something to describe the concept of connascence. So that was really cool and really memorable. What about you? Do you have a preferred way of learning new technical terms?
JOËL: I think there can be value to both approaches. But I'm with you; I think it generally is easier to add a name to a concept you already understand. And I experienced this pretty dramatically when I tried to get into functional programming.
So several years ago, I tried to learn the language Haskell which is notorious for being difficult to learn and very abstract and technical. And the way that the Haskell community typically tries to teach things is learn the fundamentals first, very top-down, learn the theory, and then, later on, you can do things in practice. So it's like before you can write an actual program, let us teach you about applicatives, and monads, and all these things that are really difficult to learn. And they're kind of scary technical terms.
So I choked out partway through, gave up on Haskell. A year later, got back into it, tried it again, choked out again. And then, eventually, I pivoted. I started getting into a similar language called Elm, which is similar syntax but compiles to JavaScript for the front end. And that community has the opposite philosophy when it comes to teaching. They want to get you productive as soon as possible. And you can learn some of the theory as you go along. And so with that, I felt like I was learning something new all the time and being productive as well, like, constantly adding new features to things in an application, and that's really exciting.
And what's really beautiful there is that you eventually learn a lot of the same concepts that you would learn in something like Haskell because the two languages share a lot of similar concepts. But instead of saying first, you need to learn about monads as a general concept, and then you can build a program; Elm says, build a bunch of programs first. We'll show you the basic syntax. And after you've built a bunch of them, you'll start realizing, wait a minute, these things all kind of look alike. There are patterns I'm starting to recognize.
And then you can just point to that and say, hey, that pattern that you started recognizing, and you see a bunch of times that's monad. You've known it all along, and now you can put a label on it. And you've gotten there. And so that's the way that I learned those concepts. And that was much easier for me than the approach of trying to learn the abstract concept first.
STEPHANIE: Monad is literally the word I just Googled earlier this week and still have a very, very hazy understanding of. So maybe I'll have to go learn Elm now. [chuckles]
JOËL: I recommend a lot of people to use that as their entry point into the statically typed functional programming world, just because of how much more shallow the learning curve is compared to alternatives. And I think a lot of it has to do with that approach of saying, let's get you productive quickly. Let's get you doing things. And eventually, patterns will emerge, and you can put names on them later. But we'll not make you learn all of the theory upfront, all the jargon.
STEPHANIE: Now that you do understand all the technical jargon around functional programming, how do you approach communicating about it when you do talk about Elm or those kinds of concepts?
JOËL: A lot of it depends on your audience. If you have an audience that already knows these concepts, then being able to use those names is really valuable because it's a shortcut. You can just say, oh yeah, this thing is a monad, and so, therefore, we can do these actions with it. And everybody in the audience just already knows monads have these properties. That's wonderful. Now I can follow to step two instead of having to have a slow build-up.
So if I'm writing an article or giving a talk, or even just having a conversation with someone, if I knew they didn't know the term, I would have to really build up to it, and maybe I wouldn't introduce the term at all. I would just talk about some of the properties that are interesting for the purpose of this particular demo.
But I would probably have to work up to it and say, "See, we have this simpler thing, and then this more complex thing. But here are the problems that we have with it. Here's a change we can make to our code that will make it work." And you walk through the process without necessarily getting into all of the theory. But with somebody else who did know, I could just say, "Oh, what we need here is monad." And they look at me, and they're like, "Oh, of course," and then we do it.
STEPHANIE: What you just described reminds me a lot of the WIRED Video Series, five levels of teaching where they have an expert come in and teach the same concept to different-aged people starting from young kids to an expert in their field as well. And I really liked how you answered that question just with the awareness that you tailor how you explain something to your audience because we could all benefit from just having that intentionality when we communicate in order to get the most value out of our interactions and knowledge sharing, and collaborative working.
JOËL: I think a theme that underlies a lot of what you and I have talked about today is just that communication, good communication is the fundamental value that we're going for here. And jargon and vocabulary can be something that empowers that but used poorly; it can also defeat that purpose. And most importantly, good communication starts with the audience, not with you. So when you work back from the audience, you can use the appropriate vocabulary and words that serve everybody and your ultimate goal of communicating.
STEPHANIE: I love that.
JOËL: So, Stephanie, thank you so much for joining us on The Bike Shed today. And as we wrap up, I wanted to ask you, what is a really fun piece of vocabulary that you’ve learned that you might want to share with the audience?
STEPHANIE: So lately, I learned the term WYSIWYG, which stands for What You See Is What You Get to describe text editing software that lets you see and edit the content as it would actually be displayed. So that was a fun, little term that someone brought up when we were paring and looking at some text editing code. And I was really excited because it sounds fun, and also, now I had just an opportunity to say it on a podcast. [laughs]
JOËL: It's amazing that an acronym that is that long has enough vowels in the right places that you can just pronounce it.
STEPHANIE: Oh yeah.
JOËL: WYSIWYG. That's a fun word to say.
STEPHANIE: 100%. I also try to pronounce all acronyms, regardless of how pronounceable they actually are. [laughs] Thanks for asking.
JOËL: With that, shall we wrap up?
STEPHANIE: Let's wrap up.
JOËL: The show notes for this episode can be found at bikeshed.fm.
This show is produced and edited by Mandy Moore.
If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show.
If you have any feedback, you can reach us at @_bikeshed, or reach me at @joelquen on Twitter, or at hosts@bikeshed.fm via email. Thank you so much for listening to The Bike Shed, and we'll see you next week. Byeeeeeeee!!!!!!
ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.Sponsored By:Airbrake: Deploy fearlessly and fix bugs faster with Airbrake Error & Performance Monitoring. Airbrake notifiers are available for all major programming languages and frameworks, and install in minutes, with an open-source SDK-based install and near-zero technical debt. Spend less time tracking down bugs and more time developing. Visit Frictionless error monitoring and performance insight for your app stack.Support The Bike Shed

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

Sep 13, 2022 • 31min
354: The History of Computing
Why does the history of computing matter? Joël and Developer at thoughtbot Sara Jackson, ponder this and share some cool stories (and trivia!!) behind the tools we use in the industry.
This episode is brought to you by Airbrake. Visit Frictionless error monitoring and performance insight for your app stack.
Sara on Twitter
UNIX philosophy
Hillel Wayne on why we ask linked list questions
History of Unix, Linux, and Open Source / Free Software
Collected Histories of Unix
Selected pages from the nine research editions of the UNIX® Programmer’s Manual illustrate the development of the system. Accompanying commentary recounts some of the needs, events, and individual contributions that shaped this evolution
These are dates that every hacker knew were important at the time, or shortly afterwards.
Unix at 50: How the OS that powered smartphones started from failure
First hand account of history of Unix and Multics by Tom Van Vleck
Transcript:
JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. And today, I'm joined by fellow thoughtboter, Team Lead, and Developer Sara Jackson.
SARA: Hello, happy to be here.
JOËL: Together, we're here to share a little bit of what we've learned along the way. So, Sara, what's new in your world?
SARA: Well, Joël, you might know that recently our team had a small get-together in Toronto.
JOËL: And our team, for those who are not aware, is fully remote distributed across multiple countries. So this was a chance to get together in person.
SARA: Yes, correct. This was a chance for those on the Boost team to get together and work together as if we had a physical office.
JOËL: Was this your first time meeting some members of the team?
SARA: It was my second, for the most part. So I joined thoughtbot, but after thoughtbot had already gotten remote. Fortunately, I was able to meet many other thoughtboters in May at our summit.
JOËL: Had you worked at a remote company before coming to thoughtbot?
SARA: Yes, I actually started working remotely in 2019, but even then, that wasn't my first time working remotely. I actually had a full year of internship in college that was remote.
JOËL: So you were a pro at this long before the pandemic made us all try it out.
SARA: I don't know about that, but I've certainly dealt with the idiosyncrasies that come with remote work for longer.
JOËL: What do you think are some of the challenges of remote work as opposed to working in person in an office?
SARA: I think definitely growing and maintaining a culture. When you're in an office, it's easy to create ad hoc conversations and have events that are small that build on the culture. But when you're remote, it has to be a lot more intentional.
JOËL: That definitely rings true for me. One of the things that I really appreciated about in-person office culture was the serendipity that you have those sort of random meetings at the water cooler, those conversations, waiting for coffee with people who are not necessarily on the same team or the same project as you are.
SARA: I also really miss being able to have lunch in person with folks where I can casually gripe about an issue I might be having, and almost certainly, someone would have the answer. Now, if I'm having an issue, I have to intentionally seek help. [chuckles]
JOËL: One of the funny things that often happened, at least the office where I worked at, was that lunches would often devolve into taxonomy conversations.
SARA: I wish I had been there for that.
[laughter]
JOËL: Well, we do have a taxonomy channel on Slack to somewhat continue that legacy.
SARA: Do you have a favorite taxonomy lunch discussion that you recall?
JOËL: I definitely got to the point where I hated the classifying a sandwich. That one has been way overdone.
SARA: Absolutely.
JOËL: There was an interesting one about motorcycles, and mopeds, and bicycles, and e-bikes, and trying to see how do you distinguish one from the other. Is it an electric motor? Is it the power of the engine that you have? Is it the size?
SARA: My brain is already turning on those thoughts. I feel like I could get lost down that rabbit hole very easily.
[laughter]
JOËL: Maybe that should be like a special anniversary episode for The Bike Shed, just one long taxonomy ramble.
SARA: Where we talk about bikes.
JOËL: Ooh, that's so perfect. I love it. One thing that I really appreciated during our time in Toronto was that we actually got to have lunch in person again.
SARA: Yeah, that was so wonderful. Having folks coming together that had maybe never worked together directly on clients just getting to sit down and talk about our day.
JOËL: Yeah, and talk about maybe it's work-related, maybe it's not. There's a lot of power to having some amount of deeper interpersonal connection with your co-workers beyond just the we work on a project together.
SARA: Yeah, it's like camaraderie beyond the shared mission of the company. It's the shared interpersonal mission, like you say. Did you have any in-person pairing sessions in Toronto?
JOËL: I did. It was actually kind of serendipitous. Someone was stuck with a weird failing test because somehow the order factories were getting created in was not behaving in the expected way, and we herd on it, dug into it, found some weird thing with composite primary keys, and solved the issue.
SARA: That's wonderful. I love that. I wonder if that interaction would have happened or gotten solved as quickly if we hadn't been in person.
JOËL: I don't know about you, but I feel like I sometimes struggle to ask for help or ask for a pair more when I'm online.
SARA: Yeah, I agree. It's easier to feel like you're not as big of an impediment when you're in person. You tap someone on the shoulder, "Hey, can you take a look at this?"
JOËL: Especially when they're on the same team as you, they're sitting at the next desk over. I don't know; it just felt easier. Even though it's literally one button press to get Tuple to make a call, somehow, I feel like I'm interrupting more.
SARA: To combat that, I've been trying to pair more frequently and consistently regardless of if I'm struggling with a problem.
JOËL: Has that worked pretty well?
SARA: It's been wonderful. The only downside has been pairing fatigue.
JOËL: Pairing fatigue is real.
SARA: But other than that, problems have gotten solved quickly. We've all learned something for those that I've paired with. It goes faster.
JOËL: So it was really great that we had this experience of doing our daily work but co-located in person; we have these experiences of working together. What would you say has been one of the highlights for you of that time?
SARA: 100% karaoke.
JOËL: [laughs]
SARA: Only two folks did not attend. Many of the folks that did attend told me they weren't going to sing, but they were just going to watch. By the end of the night, everyone had sung. We were there for nearly three and a half hours. [laughs]
JOËL: It was a good time all around.
SARA: I saw a different side to Chad.
JOËL: [laughs]
SARA: And everyone, honestly. Were there any musical choices that surprised you?
JOËL: Not particularly. Karaoke is always fun when you have a group of people that you trust to be a little bit foolish in front of to put yourself out there. I really appreciated the style that we went for, where we have a private room for just the people who were there as opposed to a stage in a bar somewhere. I think that makes it a little bit more accessible to pick up the mic and try to sing a song.
SARA: I agree. That style of karaoke is a lot more popular in Asia, having your private room. Sometimes you can find it in major cities. But I also prefer it for that reason.
JOËL: One of my highlights of this trip was this very sort of serendipitous moment that happened. Someone was asking a question about the difference between a Mac and Linux operating systems. And then just an impromptu gathering happened. And you pulled up a chair, and you're like, gather around, everyone. In the beginning, there was Multics. It was amazing.
SARA: I felt like some kind of historian or librarian coming out from the deep. Let me tell you about this random operating system knowledge that I have. [laughs]
JOËL: The ancient lore.
SARA: The ancient lore in the year 1969.
JOËL: [laughs] And then yeah, we had a conversation walking the history of operating systems, and why we have macOS and Linux, and why they're different, and why Windows is a totally different kind of family there.
SARA: Yeah, macOS and Linux are sort of like cousins coming from the same tree.
JOËL: Is that because they're both related through Unix?
SARA: Yes. Linux and macOS are both built based off of different versions of Unix. Over the years, there's almost like a family tree of these different Nix operating systems as they're called.
JOËL: I've sometimes seen asterisk N-I-X. This is what you're referring to as Nix.
SARA: Yes, where the asterisk is like the RegEx catch-all.
JOËL: So this might be Unix. It might be Linux. It might be...
SARA: Minix.
JOËL: All of those.
SARA: Do you know the origin of the name Unix?
JOËL: I do not.
SARA: It's kind of a fun trivia piece. So, in the beginning, there was Multics spelled M-U-L-T-I-C-S, standing for the Multiplexed Information and Computing Service. Dennis Ritchie and Ken Thompson of Bell Labs famous for the C programming language...
JOËL: You may have heard of it.
SARA: You may have heard of it maybe on a different podcast. They were employees at Bell Labs when Multics was being created. They felt that Multics was very bulky and heavy. It was trying to do too many things at once. It did have a few good concepts. So they developed their own smaller Unix originally, Unics, the Uniplexed Information and Computing Service, Uniplexed versus Multiplexed. We do one thing really well.
JOËL: And that's the Unix philosophy.
SARA: It absolutely is. The Unix philosophy developed out of the creation of Unix and C. Do you know the four main points?
JOËL: No, is it small sharp tools? It's the main one I hear.
SARA: Yes, that is the kind of quippy version that has come out for sure.
JOËL: But there is a formal four-point manifesto.
SARA: I believe it's evolved over the years. But it's interesting looking at the Unix philosophy and seeing how relevant it is today in web development. The four points being make each program do one thing well. To this end, don't add features; make a new program. I feel like we have this a lot in encapsulation.
JOËL: Hmm, maybe even the open-closed principle.
SARA: Absolutely.
JOËL: Similar idea.
SARA: Another part of the philosophy is expecting output of your program to become input of another program that is yet unknown. The key being don't clutter your output; don't have extraneous text. This feels very similar to how we develop APIs.
JOËL: With a focus on composability.
SARA: Absolutely. Being able to chain commands together like you see in Ruby all the time.
JOËL: I love being able to do this, for example, the enumerable API in Ruby and just being able to chain all these methods together to just very nicely do some pretty big transformations on an array or some other data structure.
SARA: 100% agree there. That ability almost certainly came out of following the tenets of this philosophy, maybe not knowingly so but maybe knowingly so. [chuckles]
JOËL: So is that three or four?
SARA: So that was two. The third being what we know as agile.
JOËL: Really?
SARA: Yeah, right? The '70s brought us agile. Design and build software to be tried early, and don't hesitate to throw away clumsy parts and rebuild.
JOËL: Hmmm.
SARA: Even in those days, despite waterfall style still coming on the horizon. It was known for those writing software that it was important to iterate quickly.
JOËL: Wow, I would never have known.
SARA: It's neat having this history available to us. It's sort of like a lens at where we came from.
Another piece of this history that might seem like a more modern concept but was a very big part of the movement in the '70s and the '80s was using tools rather than unskilled help or trying to struggle through something yourself when you're lightening a programming task. We see this all the time at thoughtbot. Folks do this many times there is an issue on a client code. We are able to generalize the solution, extract into a tool that can then be reused.
JOËL: So that's the same kind of genesis as a lot of thoughtbot's open-source gems, so I'm thinking of FactoryBot, Clearance, Paperclip, the old-timey file upload gem, Suspenders, the Rails app generator, and the list goes on.
SARA: I love that in this last point of the Unix philosophy, they specifically call out that you should create a new tool, even if it means detouring, even if it means throwing the tools out later.
JOËL: What impact do you think that has had on the way that tooling in the Unix, or maybe I should say *Nix, ecosystem has developed?
SARA: It was a major aspect of the Nix environment community because Unix was available, not free, but very inexpensively to educational institutions. And because of how lightweight it was and its focus on single-use programs, programs that were designed to do one thing, and also the way the shell was allowing you to use commands directly and having it be the same language as the shell scripting language, users, students, amateurs, and I say that in a loving way, were able to create their own tools very quickly. It was almost like a renaissance of Homebrew.
JOËL: Not Homebrew as in the macOS package manager.
SARA: [laughs] And also not Homebrew as in the alcoholic beverage.
JOËL: [laughs] So, this kind of history is fun trivia to know. Is it really something valuable for us as a jobbing developer in 2022?
SARA: I would say it's a difficult question. If you are someone that doesn't dive into the why of something, especially when something goes wrong, maybe it wouldn't be important or useful.
But what sparked the conversation in Toronto was trying to determine why we as thoughtbot tend to prefer using Macs to develop on versus Linux or Windows. There is a reason, and the reason is in the history. Knowing that can clarify decisions and can give meaning where it feels like an arbitrary decision.
JOËL: Right. We're not just picking Macs because they're shiny.
SARA: They are certainly shiny. And the first thing I did was to put a matte case on it.
JOËL: [laughs] So no shiny in your office.
SARA: If there were too many shiny things in my office, boy, I would never get work done. The cats would be all over me.
MID-ROLL AD:
Debugging errors can be a developer’s worst nightmare...but it doesn’t have to be. Airbrake is an award-winning error monitoring, performance, and deployment tracking tool created by developers for developers, that can actually help cut your debugging time in half.
So why do developers love Airbrake? It has all of the information that web developers need to monitor their application - including error management, performance insights, and deploy tracking!
Airbrake’s debugging tool catches all of your project errors, intelligently groups them, and points you to the issue in the code so you can quickly fix the bug before customers are impacted.
In addition to stellar error monitoring, Airbrake’s lightweight APM helps developers to track the performance and availability of their application through metrics like HTTP requests, response times, error occurrences, and user satisfaction.
Finally, Airbrake Deploy Tracking helps developers track trends, fix bad deploys, and improve code quality.
Since 2008, Airbrake has been a staple in the Ruby community and has grown to cover all major programming languages. Airbrake seamlessly integrates with your favorite apps to include modern features like single sign-on and SDK-based installation. From testing to production, Airbrake notifiers have your back.
Your time is valuable, so why waste it combing through logs, waiting for user reports, or retrofitting other tools to monitor your application? You literally have nothing to lose. Head on over to airbrake.io/try/bikeshed to create your FREE developer account today!
JOËL: So we've talked a little bit about Unix or *Nix, this evolution of systems. I've also heard the term POSIX thrown around when talking about things that seem to encompass both macOS and Linux. How does that fit into this history?
SARA: POSIX is sort of an umbrella of standards around operating systems that was based on Unix and the things that were standard in Unix. It stands for the Portable Operating System Interface. This allowed for compatibility between OSs, very similar to USB being the standard for peripherals.
JOËL: So, if I was implementing my own Unix-like operating system in the '80s, I would try to conform to the POSIX standard.
SARA: Absolutely. Now, not every Nix operating system is POSIX-compliant, but most are or at least 90% of the way there.
JOËL: Are any of the big ones that people tend to think about not compliant?
SARA: A major player in the operating system space that is not generally considered POSIX-compliant is Microsoft Windows.
JOËL: [laughs] It doesn't even try to be Unix-like, right? It's just its own thing,
SARA: It is completely its own thing. I don't think it even has a standard necessarily that it conforms to.
JOËL: It is its own standard, its own branch of the family tree.
SARA: And that's what happens when your operating system is very proprietary. This has caused folks pain, I'm sure, in the past that may have tried to develop software on their computers using languages that are more readily compatible with POSIX operating systems.
JOËL: So would you say that a language like Ruby is more compatible with one of the POSIX-compatible operating systems?
SARA: 100% yes. In fact, to even use Ruby as a development tool in Windows, prior to Windows 10, you needed an additional tool. You needed something like Cygwin or MinGW, which were POSIX-compliant programs that it was almost like a shell in your Windows computer that would allow you to run those commands.
JOËL: Really? For some reason, I thought that they had some executables that you could run just on Windows by itself.
SARA: Now they do, fortunately, to the benefit of Ruby developers everywhere. As of Windows 10, we now have WSL, the Windows Subsystem for Linux that's built-in. You don't have to worry about installing or configuring some third-party software.
JOËL: I guess that kind of almost cheats by just having a POSIX system embedded in your non-POSIX system.
SARA: It does feel like a cheat, but I think it was born out of demand. The Windows NT kernel, for example, is mostly POSIX-compliant.
JOËL: Really?
SARA: As a result of it being used primarily for servers.
JOËL: So you mentioned the Ruby tends and the Rails ecosystem tends to run better and much more frequently on the various Nix systems. Did it have to be that way? Or is it just kind of an accident of history that we happen to end up with Ruby and Rails in this ecosystem, but just as easily, it could have evolved in the Windows world?
SARA: I think it is an amalgam of things. For example, Unix and Nix operating systems being developed earlier, being widely spread due to being license-free oftentimes, and being widely used in the education space. Also, because it is so lightweight, it is the operating system of choice. For most servers in the world, they're running some form of Unix, Linux, or macOS.
JOËL: I don't think I've ever seen a server that runs macOS; exclusively seen it on dev machines.
SARA: If you go to an animation company, they have server farms of macOS machines because they're really good at rendering. This might not be the case anymore, but it was at one point.
JOËL: That's a whole other world that I've not interacted with a whole lot.
SARA: [chuckles]
JOËL: It's a fun intersection between software, and design, and storytelling. That is an important part for the software field.
SARA: Yeah, it's definitely an aspect that deserves its own deep dive of sorts. If you have a server that's running a Windows-based operating system like NT and you have a website or a program that's designed to be served under a Unix-based server, it can easily be hosted on the Windows server; it's not an issue. The reverse is not true.
JOËL: Oh.
SARA: And this is why programming on a Nix system is the better choice.
JOËL: It's more broadly compatible.
SARA: Absolutely. Significantly more compatible with more things.
JOËL: So today, when I develop, a lot of the tooling that I use is open source. The open-source movement has created a lot of the languages that we know and love, including Ruby, including Rails. Do you think there's some connection between a lot of that tooling being open source and maybe some of the Unix family of operating systems and movements that came out of that branch of the operating system family tree?
SARA: I think that there is a lot of tie-in with today's open-source culture and the computing history that we've been talking about, for example, people finding something that they dislike about the tools that are available and then rolling their own. That's what Ken Thompson and Dennis Ritchie did. Unix was not an official Bell development. It was a side project for them.
JOËL: I love that.
SARA: You see this happen a lot in the software world where a program gets shared widely, and due to this, it gains traction and gains buy-in from the community. If your software is easily accessible to students, folks that are learning, and breaking things, and rebuilding, and trying, and inventing, it's going to persist. And we saw that with Unix.
JOËL: I feel like this background on where a lot of these operating systems came but then also the ecosystems, the values that evolved with them has given me a deeper appreciation of the tooling, the systems that we work with today. Are there any other advantages, do you think, to trying to learn a little bit of computing history?
SARA: I think the main benefit that I mentioned before of if you're a person that wants to know why, then there is a great benefit in knowing some of these details. That being said, you don't need to deep dive or read multiple books or write papers on it. You can get enough information from reading or skimming some Wikipedia pages.
But it's interesting to know where we came from and how it still affects us today. Ruby was written in C, for example. Unix was written in C as well, originally Assembly Language, but it got rewritten in C. And understanding the underlying tooling that goes into that that when things go wrong, you know where to look.
JOËL: I guess that that is the next question is where do you look if you're kind of interested? Is Wikipedia good enough? You just sort of look up operating system, and it tells you where to go? Or do you have other sources you like to search for or start pulling at those threads to understand history?
SARA: That's a great question. And Wikipedia is a wonderful starting point for sure. It has a lot of the abbreviated history and links to better references. I don't have them off the top of my head. So I will find them for you for the show notes. But there are some old esoteric websites with some of this history more thoroughly documented by the people that lived it.
JOËL: I feel like those websites always end up being in HTML 2; your very basic text, horizontal rules, no CSS.
SARA: Mm-hmm. And those are the sites that have many wonderful kernels of knowledge.
JOËL: Uh-huh! Great pun.
SARA: [chuckles] Thank you.
JOËL: Do you read any content by Hillel Wayne?
SARA: I have not.
JOËL: So Hillel produces a lot of deep dives into computing history, oftentimes trying to answer very particular questions such as when and why did we start using reversing a linked list as the canonical interview question? And there are often urban legends around like, oh, it's because of this. And then Hillel will do some research and go through actual archives of messages on message boards or...what is that protocol?
SARA: BBS.
JOËL: Yes. And then find the real answer, like, do actual historical methodology, and I love that.
SARA: I had not heard of this before. I don't know how. And that is all I'm going to be doing this weekend is reading these. That kind of history speaks to my heart. I have a random fun fact along those lines that I wanted to bring to the show, which was that the echo command that we know and love in the terminal was first introduced by the Multics operating system.
JOËL: Wow. So that's like the most common piece of Multics that as an everyday user of a modern operating system that we would still touch a little bit of that history every day when we work.
SARA: Yeah, it's one of those things that we don't think about too much. Where did it come from? How long has it been around? I'm sure the implementation today is very different. But it's like etymology, and like taxonomy, pulling those threads.
JOËL: Two fantastic topics. On that wonderful little nugget of knowledge, let's wrap up. Sara, where can people find you online?
SARA: You can find me on Twitter at @csarajackson.
JOËL: And we will include a link to that in the show notes.
SARA: Thank you so much for having me on the show and letting me nerd out about operating system history.
JOËL: It's been a pleasure.
The show notes for this episode can be found at bikeshed.fm.
This show is produced and edited by Mandy Moore.
If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes. It really helps other folks find the show.
If you have any feedback, you can reach us at @_bikeshed or reach me @joelquen on Twitter or at hosts@bikeshed.fm via email.
Thank you so much for listening to The Bike Shed, and we'll see you next week. Byeeeeee!!!!
ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.Sponsored By:Airbrake: Deploy fearlessly and fix bugs faster with Airbrake Error & Performance Monitoring. Airbrake notifiers are available for all major programming languages and frameworks, and install in minutes, with an open-source SDK-based install and near-zero technical debt. Spend less time tracking down bugs and more time developing. Visit Frictionless error monitoring and performance insight for your app stack.Support The Bike Shed

Sep 6, 2022 • 38min
353: Mental Models
Mental models are metaphors that help us understand complex problems we work on. They can be a simplified roadmap over an infinite area of complexity.
How does one come up with mental models? How are they useful? Are they primarily a solo thing, or can they be used to communicate with the team? What happens when your model is inaccurate? Today, Joël is joined by Eebs Kobeissi, a Developer and Dev Manager at You Need a Budget, to discuss.
This episode is brought to you by Airbrake. Visit Frictionless error monitoring and performance insight for your app stack.
Eebs on Twitter
You Need a Budget
Skill floors and skill ceilings
Transcript:
JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. And today, I'm joined by Eebs Kobeissi, a Developer and Dev Manager at You Need a Budget.
EEBS: Hi, Joël. It's really good to be here.
JOËL: And together, we're here to share a little bit about what we've learned along the way. So, Eebs, what's new in your world?
EEBS: Oh, a whole lot. I'm a new dad, so I'm getting to experience all those things. But in the developer world, I've recently picked up programming on an ESP32, which controls LED lights. And so I'm having fun lighting up my office.
JOËL: Is that like one of those little microboards, kind of like a Raspberry Pi?
EEBS: Yeah, exactly. It's a little board that's compatible with the Arduino IDE. And I literally only played with it last weekend, so it's still very new to me.
JOËL: Nice. Have you done any Arduino development or Raspberry Pi or anything like that before?
EEBS: No, I have a Raspberry Pi that I run like a DNS server on, but I haven't done any actual programming. I did make an LED blink, which is pretty cool.
JOËL: What kind of programming is required for a board like that?
EEBS: From my understanding, it's either in Python or C. Those are, I think, the two languages that you can program on it. I definitely do not know C. And so I'm just going through a bunch of tutorials and reading some sample code. But I think if I ever end up trying to implement something more complex, I'll probably switch over to Python because that's a little more familiar.
JOËL: So the coding feels fairly high level even though you're writing controller code for LEDs.
EEBS: I hope so. I'd love to be able to take advantage of whatever abstractions I can.
JOËL: Do you have any fun goals you're trying to do with this? Or is this just for the fun of trying a completely different environment than web development?
EEBS: No, it's actually rooted in something visual. So I have these shelves behind me that are in my webcam when I'm in meetings or whatever. And so I want to be able to put a light strip across these shelves and have some sort of visual thing in the background.
JOËL: Like LED mood ring?
EEBS: Yeah, kind of. My eventual goal would be that as I'm talking, a little equalizer display pops up behind me. I thought that would be pretty neat.
JOËL: That is amazing. That will give you all of the cred in the meetings.
EEBS: Right? I thought that'd be pretty cool. What have you been thinking about recently, Joël?
JOËL: I've been submitting to the RubyConf call for proposals which, as of the recording of this episode, has just closed this week. And like many people, I submitted on the last day.
EEBS: [laughs]
JOËL: And it was really fun trying to take some ideas that I'm excited about and then turn them into a proposal that is accessible to other people.
EEBS: Nice. Do you want to share a little bit about what the talk is, or is it under wraps for now?
JOËL: I don't know if anyone on the committee will listen to this before the review goes out. This might break the anonymity of the proposal.
EEBS: Oh, right, right.
JOËL: One thing I will share that's interesting is that there are topics that I'm excited about. It's like, oh, here are a bunch of cool things about something, some technical topic. But talks that are just ten cool things about X are not that great. And so I needed to find some sort of unifying idea that I could use to share that. And that generally is in the form of trying to find a story that I can tell. What unifies all of these things together? What tells a compelling story? Is there some metaphor I can lean into?
EEBS: Nice. I think that's a really powerful way of communicating something deeper is through telling something that people can relate to.
JOËL: One way that thinking about metaphors has been really impactful for me recently is the idea of mental models and how those can help us in development. I'm curious; we've thrown around the phrase a little bit you and I in past conversations; what does a mental model mean to you?
EEBS: I tend to be a visual thinker. And from talking to others, I've heard similar statements. So for me, a mental model is how I think about a particular domain or how I think about code flow or structure. And for me, it's usually either as two-dimensional objects or occasionally three-dimensional objects that I have floating in my visual space.
So, for example, if we had two classes that are collaborators in some way, I often think of them maybe as two rectangles that are side by side. And when they interact, there's some little amorphous blob from one of those rectangles that reaches out into the other one or passes a message from one to the other.
And I sort of have this idea of how many connections are there between these two physical things. Or, if I'm thinking about code flow and the path of execution that code might take, sometimes I visualize it as maybe a tree or potentially loops if there are such cases.
JOËL: So when you think of these concepts, just in general, you're seeing in your mind's eye squares and rectangles floating in the air.
EEBS: Yeah, pretty often. Sometimes it takes those shapes, and as I build up a mental model of some code, I'm usually adding new shapes into that picture I have in my mind. I tend to view things sort of top-down. So like, the start of code or the start of execution is usually at the top or maybe the far left or far right.
And as execution happens, I usually view that as moving in towards the middle and potentially going back out when a response is returned. If it's a web request, something like that, I view it as this sort of outside in. And there's a bunch of pieces in there that are all talking to each other.
JOËL: That's really cool. So not only is there a geometric aspect to it, but there's a spatial aspect to it as well.
EEBS: Yeah. And it's interesting, like, I haven't actually thought about it [laughs] in this level of detail before. But yeah, there certainly is a spatial aspect to it. And I have this idea in my mind of like things and domain objects kind of belong at the bottom, and they should have well-defined boundaries. But the pieces that are a little bit towards the outer edges may be a little more fuzzy and may have less definition around them.
JOËL: That's really interesting because I also have this sort of in my mind's eye see these things when I'm thinking about concepts like that. But I've talked to other people, and some people don't even have much of a mind's eye at all. They don't tend to visualize things in their mind in that way.
EEBS: Yeah, it's really interesting how different people approach this thinking about code. A lot of people write things down. And I write things down, too, and draw little arrows that don't really make any sense. But it helps me do something physically sometimes as well as just thinking about it.
JOËL: Have you ever tried to convert these pictures you see in your mind and actually draw them on paper?
EEBS: Occasionally. And for the most part, that usually takes the form of some kind of domain modeling, whether it's based on database tables or just domain objects. And sometimes I will try and draw them out and then specify the relationships between them like, oh, you know, this one model talks to this other model in this particular way. And I'll define a relationship between them, which helps me think about them and how they interact.
JOËL: I've found that even though for some things I can see it very vividly in my mind's eye, I struggle to then concretely translate that onto paper or digital paper if you will. It's almost like trying to, say, translate an emotion into words and that even though I feel like I see a visual picture, I can't reproduce it by drawing necessarily.
EEBS: It's interesting you brought up feeling because a lot of the times, I have this gut feeling about a mental model, like whether I think it is correct or not. And sometimes I have this uneasy feeling of, like, that doesn't feel right to me, but it's hard to articulate why. And I think sometimes that's when I have to pull out something physical, start making those relations, start connecting things.
And that's when I might uncover, like, oh, this feels odd because I have a circle here or a cycle or something. Or I've sort of represented the truth of something in two different places. Do you have any techniques for getting it out of your head and into something physical that you could share with someone else, maybe it's text or a picture?
JOËL: I think I do struggle with that conversion sometimes. Practice definitely helps. I think maybe there is a metaphor here between converting these, let's call them, pictures that I see in my mind's eye and then drawing diagrams with trying to take feelings and expressing them in words. In the same way that, maybe I might have some feelings, and then I want to journal how I feel, and I struggle to express that.
But finding a way to express that gives me a certain amount of precision and a more concrete thing. In the same way, these things that flash in front of my mind's eye, if I can take the time to put them on paper, they're now more real. They're more concrete. I think you can probe the edges, the ways that it kind of falls apart more easily.
EEBS: Yeah, that makes a lot of sense. There's a lot of value in writing that down and going through those details in a methodical way because oftentimes, you'll catch inconsistencies, or you'll find better ways to describe it. And being able to share your mental model with someone else is often...well, it can be really tricky.
And I think that's why it's important to go through and maybe find a common medium that you can share because I can't see into your brain. You can't see into mine. But if we can share our mental models, then hopefully, we have a better chance of agreeing on the solution or finding inconsistencies.
JOËL: Exactly. I think, in many ways, there are almost multiple layers of mental models and that you might have an abstraction or a metaphor for a concept that you're working with separate from the diagram. And then the diagram is yet another metaphor, but now we're going geometric to represent a broader idea.
EEBS: Yeah. Are there any other ways that you take that picture from your mind's eye besides written documents or conversations? Do you use any diagramming tools that specifically help with that? Or is it just kind of free-form?
JOËL: I do a mix. I am a big fan of draw.io, which allows you to just free-hand or pull shapes together, things like that. There are some more structured tools that I will use. I'll use Mermaid.js.
EEBS: Yeah, I've been using that a lot too.
JOËL: Yeah, that's great. I've been digging into more structured diagrams recently, particularly the idea of graphs, directed graphs. And those have interesting properties.
EEBS: Can you share a little more detail about what you mean?
JOËL: So a graph in the computer science sense is a bunch of nodes. They are typically represented as circles and then edges which are the connections between them. A directed graph is now there's an arrow pointing in a particular direction. A really interesting property that you can have with directed graphs is whether or not they include cycles. So can you only by following the arrows effectively create a loop? Or will the arrows always lead you to some kind of terminal node?
EEBS: Gotcha. Is that a directed acyclic graph?
JOËL: If there are no cycles, yes, it is a directed acyclic graph or DAG, as you'll often see it abbreviated.
EEBS: [laughs] How do you relate that graph to code? And what benefits do you get from expressing it that way?
JOËL: So this shows up in a lot of places. And I'd even say that thinking of certain aspects of my code as a graph and a potentially directed acyclic graph is itself a mental model or a metaphor that helps bring clarity to the way I think about things. So, for example, code, you know, you invoke some main function at some point to call the code, and then that's going to call out some other functions, which call out some other functions, and so on. You may have heard that referred to as a call graph. But that is a graph of calls.
There might be cycles in there for co-recursive functions and things like that. But that is one way you can then sift through and analyze how control flow or how logic flows through your application is through a function graph. You mentioned earlier the idea of objects and how they're connected to each other. That's an object graph.
EEBS: Right. Recently, I had to work through a state transition problem where a customer has some billing, and they can go through many different states, whether it's active, or canceled, or past due, those sorts of things. And so actually, I reached for Mermaid.js and built a graph of, okay, they start here in this empty state. And then they subscribe, which then they become active. They might cancel their subscription, which moves them to a different state.
And by listing out all the states and the transitions between them, it helped me to understand what methods I might need to define on which objects in order to allow those transitions to happen and what checks I might need to make before allowing those transitions depending on the state of the system.
JOËL: I'm hearing the keywords states and transitions. And that's making me think of finite-state machines. Are you drawing a finite-state machine graph or something a bit more free-handed?
EEBS: It's a bit more of free-handed. I don't think I've actually drawn out a state machine since college but just representing the different states as different boxes and the transitions that are possible from those states. I mean, I guess that kind of is a state machine in some way. So graphs are great visual approaches. Are there any non-visual approaches that you take?
JOËL: That's a great question because not all mental models have to be visual. I think the power of a mental model exists in a metaphor. And one that's kind of broad but that I've applied to a lot of different areas is the general idea of something being parallel or in series. I think I first came across this concept talking about electric circuits. And are we talking about two little light bulbs that are in parallel, and if the electricity to one is cut, the other one still lights up? Or are they chained together in series?
EEBS: Yeah, like my LEDs.
JOËL: Exactly, going back to Arduino, but it can also be applied to a bunch of other things. We can talk about code being in parallel or in series. We can talk about work being in parallel or in series. Interestingly, I took that mental model as a sort of quick shortcut when I was digging into some functional programming ideas. Monads and applicatives are the fancy terms here.
EEBS: Oh boy, I'm ready.
JOËL: In general, and there's a hefty asterisk here, I think of monads as being serial, so you're chaining something; one thing happens, then another. So you can think of, for example, chaining promises in JavaScript, promise one, then promise two, as opposed to applicatives which are parallel. So you might think of maybe zipping two lists or two arrays in Ruby. The two arrays, there are no dependencies between the two of them. They get processed side by side as you're traversing both of them together.
EEBS: Interesting. I've heard the term monad a lot, but I haven't heard the term applicative. Are there any other details you can share about them and what makes them different or how they might be seen in our code?
JOËL: I think that the key difference is that distinction in how they're processed. Applicatives are a way of combining two independent, let's call them data sources, and then you find a way to combine them together. So it could be two independent arrays, and you're zipping through them. It might be two independent HTTP requests, and they can both fire in parallel. But then you want to combine their outputs. So you say wait until both are successful and then combine their output.
EEBS: Oh, okay, gotcha.
JOËL: It could even be nullable values. So you say do this thing if both values are present. But you're not...the value of one or the fact that one is null or not is not dependent on whether the other one is null or not. They're independently null or not as opposed to something...Monads are, again, a different way of combining. You might call them data sources or operations. But in this case, there is a clear dependency one, and then its output influences the next one.
You might say check the value is null or present or not. And then, if it is present, take that value and then put it as the input of my next operation. And then, if it is null or not, do another thing. See, now you have a sort of chain.
EEBS: Where do you see these chains happening in code? Or is it everywhere?
JOËL: Once you know that pattern which, again, could be thought of as another mental model, you start seeing it everywhere. So promises in JavaScript chaining together that's effectively monads. Don't @ me, all the functional programming people.
EEBS: [laughs]
JOËL: I know that's not quite true. Anything dealing with multiple operations that could succeed or fail depending on, again, whether you're treating them as dependent or independent, that's probably going to look very similar to either monad or applicative.
EEBS: So the first thing that actually comes to mind here is things like background jobs. Using Sidekiq or Resque or other job processors, you can have a queue of jobs that need to be executed, and they might need to run in serial, or potentially you have multiple workers pulling from a single queue, and thus the work is happening in parallel. Is that a reasonable analogy?
JOËL: I think it's good for the serial versus parallel, but it's not necessarily a good analogy for understanding monads and applicatives.
EEBS: Gotcha.
JOËL: So with two workers, you can process a queue in parallel, and a bunch of things happen.
EEBS: But there's not necessarily anything that is bringing those two workers together to produce a single output.
JOËL: Yes. And there's no dependency between the tasks in the queue.
EEBS: Right, right, gotcha.
JOËL: So if you have a task that says execute this task and then only if this task succeeds, then do the second task, now you've created a dependency. And you couldn't process that in parallel because if task one, which has to be executed first, is executed by worker one, task two should not get processed unless task one is successful. You can't just say, oh, I've got another worker free. I haven't processed task two because it's waiting to know does task one succeed.
EEBS: Right. So an example in code would be a user creates a new order. And when they create a new order, we send them a confirmation email. That would be an example of that happening in serial or a monad-like thing. [chuckle]
JOËL: Yes, I found that thinking of things as serial or parallel is a good shortcut for thinking about monads and applicatives. I don't know that the reverse is necessarily true. They don't necessarily transfer one-to-one with each other. And maybe that's a danger of mental models, right? You find a mental model that describes a situation, and then you try to reverse it, and then you make false assumptions about the world.
MID-ROLL AD:
Debugging errors can be a developer’s worst nightmare...but it doesn’t have to be. Airbrake is an award-winning error monitoring, performance, and deployment tracking tool created by developers for developers that can actually help cut your debugging time in half.
So why do developers love Airbrake? It has all of the information that web developers need to monitor their application - including error management, performance insights, and deploy tracking!
Airbrake’s debugging tool catches all of your project errors, intelligently groups them, and points you to the issue in the code so you can quickly fix the bug before customers are impacted.
In addition to stellar error monitoring, Airbrake’s lightweight APM helps developers to track the performance and availability of their application through metrics like HTTP requests, response times, error occurrences, and user satisfaction.
Finally, Airbrake Deploy Tracking helps developers track trends, fix bad deploys, and improve code quality.
Since 2008, Airbrake has been a staple in the Ruby community and has grown to cover all major programming languages. Airbrake seamlessly integrates with your favorite apps to include modern features like single sign-on and SDK-based installation. From testing to production, Airbrake notifiers have your back.
Your time is valuable, so why waste it combing through logs, waiting for user reports, or retrofitting other tools to monitor your application? You literally have nothing to lose. Head on over to airbrake.io/try/bikeshed to create your FREE developer account today!
JOËL: Another mental model that is not necessarily visual that I like actually comes from the video game community, and that's thinking of skill ceilings and skill floors. So in, I think, particularly the MOBA Community, that's a Multiplayer Online Battle Arena, they'll talk about characters as having a high skill floor or a low skill ceiling.
And generally, what that means, and again, the meaning varies a little bit by community, is that a character with a low-skill floor is an easily accessible character. They might not have a lot of skill shots, like, you press a button, and things happen around your character. You don't need to aim, things like that. A high skill ceiling means that there's a lot of room for you to grow, and as you get more skilled, you can get significantly better with that character.
EEBS: Gotcha. So the opportunity is greater with a higher skill ceiling.
JOËL: Correct. And depending on how the character is set up, you might have a very narrow range that could be in the low range where it has a low skill floor and a low skill ceiling, which means that the character is easy to learn. But once you've learned it, there's not really a lot you can do with it. It's a fairly basic character. So getting better at the game is not necessarily going to make you that much more impactful.
And then you could have one that's the opposite that is high both skill floor and skill ceiling where a character is very hard to learn. But once you learn it, that's kind of all there is to it. And then you might have one that has a large range somewhere; maybe it's easy to learn, but it's hard to master, or there's a lot of room for growth.
And so, taking this framework for analyzing characters and video games, I think we can apply that to technology in general. This could be language design. This could be just API design. And you might say, well, I want this to be very accessible. People can jump in very easily. You might say I want this to be very powerful and have a lot of high-end features that make your power users very happy and very productive.
EEBS: That's interesting. When you first were talking about it, I was actually less thinking about it from a user's perspective of what maybe they could do in the application but potentially from the standpoint of a developer writing the system itself.
One of the pieces I always come back to in software development is that change is inevitable. And so, making something easy to change often pays great benefits down the road. And so I wonder how that fits into this idea of a low skill ceiling or a high skill ceiling in terms of perhaps flexibility or being decoupled such that you can take one idea and easily extend it or easily get more from it than you originally set out to build.
JOËL: There's often a trade-off. So you make something easy to change. It's highly decoupled. But you maybe introduce more indirection to the system. So while it's easier to change one single piece, it's harder to understand the system as a whole.
EEBS: Yeah, that's true. And sometimes, you bake in assumptions that you make about the future, which turn out not to be true.
JOËL: [laughs] Yes, that is definitely something I'm guilty of.
EEBS: I think we all are.
JOËL: One thing that I find interesting is as you evolve the design of an architecture pattern, a system, a whole language, you might want to move one of those if I think of them like two independent sliders on a one-dimensional scale. So maybe you want to move the upper boundary a little bit and say I want a higher skill ceiling for this, but they don't actually move completely independently.
So introducing some advanced features might inadvertently also raise the skill floor. And conversely, making the language super accessible so that it has a low-skill floor, you might have to decide I will not introduce certain features.
EEBS: One thing I wanted to ask you about is, do you view different languages as having different skill floors and ceilings? And, you know, I love Ruby. I know you love Element. I've played with Element. It's been a great learning tool for me. How do you view those two languages in terms of skill ceilings and skill floors in terms of, I guess, what you can do with them?
JOËL: That's a great question. And I think you can definitely apply that to languages. Admittedly, I think you could probably start a lot of flame wars with that.
EEBS: [chuckles] Let's not do that.
JOËL: I wrote an article a while back where I applied that mental model to look at the F# programming language. And there was a debate in that community about certain features to add and whether they would allow advanced programming but potentially at the cost of accessibility to newer members of the community and how to balance those. And so I thought, hey, let's throw this video game metaphor at the problem and talk about it through that lens.
EEBS: That's really cool. Did you draw any conclusions, or was it as a way to start a conversation?
JOËL: It is a way to start a conversation. I don't think there is a single correct or best distribution of your skill, ceiling, and floor. It has to match the goals you set out for your project. Just like in games, people love to rank which characters are best and not. And sometimes you can show that, in general, this character is better.
But oftentimes, in a balanced game, you can talk about this character being easier to get started with or this character working very well if you're a pro. But the fact that you have a higher or lower skill ceiling or floor doesn't necessarily make the character better or worse.
EEBS: So, this conversation about differing mental models, I think I hadn't realized that there can be so many different types of mental models. And some things that I do in my thinking I haven't classified as a mental model. But now that you bring it up, I think one that I think about fairly often is this idea of two objects that are collaborators and reaching into the internals of one of those objects from the other object.
So A and B are two separate things. And if A reaches into B's bucket and messes with the state of B, I view that as sort of a bad practice. You're not really adhering to maybe the public API that that object is exposing. You're kind of reaching in and going around behind its back and changing some stuff that it may not expect.
JOËL: Would you refer to that maybe as tight coupling?
EEBS: Yeah, it's definitely tight coupling. It's not just tightly coupled; it's almost worse than that. It's almost like going behind somebody's back and making a change without them knowing. And so when I see that in code or when I write code that does that, I have this really intense desire to separate that and to say, no, no, you can't go in and update this record directly in the database. You have to send it a message and say, "Hey, I would like you to be aware of something," and then it goes and changes its own internal state as a response to that.
And so I have this very vivid sort of mental feeling of it being wrong, of it being like, I'm being sneaky, or I'm not being gracious to the person I'm interacting with as though I were one of these objects.
JOËL: That's fascinating. You've practically anthropomorphized these objects.
EEBS: I do. I view them as little people.
JOËL: You describe this interaction as going behind someone's back. That is the thing that I, a person, do to someone else. It's not a function making a direct call. And yet, it's such a strong...we use a social mental model to talk about objects and interactions.
EEBS: Yeah, I almost want them to be friends. And I think that applies to real-life relationships, right? If you have a nice dialogue back and forth, there's an understanding. There's commonality that you can find. But if I were to go do something behind your back without chatting with you about it first, you might not be so happy with me.
JOËL: I'd feel betrayed.
EEBS: Right.
JOËL: I feel like there's probably a really fun conference talk to be done about that. We often use that metaphor; I think when talking about objects sort of subconsciously but making it explicit and just being, hey, let's talk about these objects as if they were people. Why don't we want to do this? Because this one here is betraying the other object there. This one here is being impolite.
EEBS: We could have two people get on stage and talk to each other. And I might then go and reach in your pocket and pull out some change without you knowing, and you might be upset with me.
JOËL: That would be great. Get a little skit going up on stage. Or even if you're artistically inclined, you could probably draw some really fun little characters to illustrate this.
EEBS: That would be really cool. I, unfortunately, don't have the artistic talent to do that.
JOËL: Well, free conference talk idea to all listeners of the podcast. I expect to see this for RailsConf 2023, maybe.
EEBS: I'll be looking for it. So I've shared a mental model that I didn't really know was a mental model. Are there other mental models that you want to share that I may not be thinking of?
JOËL: Here's one that I've just come to realize recently that I'm actually quite excited about: when you think about the word refactoring, how would you describe that idea?
EEBS: Well, refactoring to me is changing the implementation without changing the behavior.
JOËL: Yes, I think that is the classical definition. You should be able to change the implementation of a method, and the tests without changing are still green after you've done that.
EEBS: I guess, mentally, I think about that as perhaps drawing a box around some of the objects that are floating in my mind's eye, rearranging how they exist within that box, and then the box dissolves. And the tests still pass, but the structure of the objects or the code has changed in my mind.
JOËL: I love that you immediately went to a visual approach there. And I think I have something similar, but I'm coming at it from a slightly more domain modeling perspective. So thinking maybe less from an individual method approach but looking at maybe a larger system, what you're trying to do is use code to describe some version of reality. So it might be a business process that you have. It might be trying to describe some aspect of your customer's life that you're trying to automate for them.
Oftentimes, this thing you're trying to describe in code terms is going to be a simplification because life has a ton of edge cases, and many of them we don't care about. So if we go with a visual metaphor here, you're trying to draw some kind of shape using only straight lines to approximate some weird curve.
And so, let's say you draw something with only four lines. It's really simple, how you have a diamond. That's the shape you're trying to create. And then you're going to fill it in with little other shapes that approximate a diamond. And those are your different models and functions and all the other components that we use to build software.
At some point, your understanding of the underlying reality might change. Maybe you need more precision, or maybe the actual feature requirements have changed. The thing you're trying to approximate with your code is not a diamond. Maybe you've added a few more sides to it. It's a pentagon. So we've gone from four sides to five. And the little components, and modules, and things that you have there approximate that diamond work.
They still mostly approximate your pentagon, but it's really clunky because the initial design was to approximate something else. They were really good for fitting in really tightly and being very loosely coupled to each other when we were trying to do a diamond, but then they don't work as well in the pentagon.
EEBS: So maybe some of the internal shapes need to change or adjust to fill the space that the pentagon has now created.
JOËL: To fill the space or maybe even just to fill it in a way that's less clunky. And so the idea here in this metaphor is that the reality we're targeting in software is always changing. And so the underlying reality changes, and so we're changing that shape that we're creating all the time.
But also, we're getting more precision as we decide; oh, we care about this edge case now. We didn't in version one, and so as part of that, we're constantly having to take the modules that maybe were very well designed initially but then restructure them to fit the new requirements because now there's a fourth object coming in, and it's kind of clunky with our current configuration.
EEBS: That's interesting. One of the first things that jumps to mind is that maybe there are better ways or worse ways to do that refactoring to fit that new shape. Do you think there's any truth to that in the sense that you might initially design a system that perfectly fits that diamond or very closely fits that diamond but then as it changes to a pentagon, do you need to simply add a new piece to fill in that empty space? Or do you need to restructure everything within the diamond now to fit the shape of the pentagon?
JOËL: Oftentimes, you do need to restructure. And I think there's this wonderful little phrase from; I believe it's Kent Beck that says, "Make the change easy, and then make the easy change."
EEBS: Yep.
JOËL: And so, to me, that makes the change easy is that initial restructuring that you need to do of those first shapes so that you can finally bring in the new one.
EEBS: Oh, that's a cool visual. I immediately can imagine the pieces in the pentagon moving around to make space for a new piece that you need to now bring in. And that movement of all those pieces can be really difficult.
Have you ever played that game where it's a square, and you're trying to get a ship out of a port, but there's a whole bunch of other ships, and you can only move them left and right and up and down? And you can do that. And that's what I'm picturing right now is moving shapes within that pentagon to then make space for either a new shape or to allow a shape to escape that is no longer relevant.
JOËL: I played a version of that that had cars, cars, and trucks.
EEBS: Gotcha. Yeah, I think I played that too.
JOËL: That would also be a fun conference talk, right? Like, start with that game as your initial metaphor. And then you use that as a way to talk about refactoring.
EEBS: That would be really cool.
JOËL: I would watch that talk. To anybody listening who wants to give that talk, I want to see you at RailsConf 2023.
EEBS: [laughs] Are we just a talk factory now?
[laughter]
JOËL: I love talk ideas. Maybe this should become a segment. Just have Eebs come in for five minutes once a month and give us a talk idea. It could even be fun to see a talk idea that multiple people implemented differently.
EEBS: That would be really cool, actually. I always get nervous about giving talks or being on podcasts like this one. I would love to be the person that gets to sit there and throw out random ideas and have other people fulfill my dreams.
JOËL: Well, thank you so much, Eebs, for joining us to talk about mental models. And to all of our listeners, I'd love to hear about what mental models you find are helpful, and so please share them with us. On Twitter, you can reach us at @_bikeshed.
EEBS: Thanks for having me, JOËL. This has been super fun.
JOËL: And on that note, let's wrap up. The show notes for this episode can be found at bikeshed.fm. This show is produced and edited by Mandy Moore.
If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show.
If you have any feedback, you can reach us at @_bikeshed or reach me at @joelquen on Twitter or at hosts@bikeshed.fm via email.
Thank you so much for listening to The Bike Shed, and we'll see you next week. Byeeeeeee!!!!!!
ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.Sponsored By:Airbrake: Deploy fearlessly and fix bugs faster with Airbrake Error & Performance Monitoring. Airbrake notifiers are available for all major programming languages and frameworks, and install in minutes, with an open-source SDK-based install and near-zero technical debt. Spend less time tracking down bugs and more time developing. Visit Frictionless error monitoring and performance insight for your app stack.Support The Bike Shed

Aug 30, 2022 • 32min
352: Case Expressions
As developers, we care a lot about code quality. How do we know how good is good enough? When do we stop improving code? Alternatively, when working on code that's really bad, how much do you improve it before calling it a day? thoughtbot's Stephanie Minn joins Joël to chat about this and case expressions: We recently discussed these as part of thoughtbot's RubyScience reading group. Are case expressions bad? Are they equivalent to multi-way conditionals? When do you use polymorphism?
This episode is brought to you by Airbrake. Visit Frictionless error monitoring and performance insight for your app stack.
RubyConf 2022
RubyConf Mini
Stephanie's talk at RubyConf 2021
WNB.rb
Joël's RailsConf 2022 talk
Ruby Science
older episode on wizards
TCR
Transcript:
JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Joël Quenneville. And we're here to share a little bit about what we've learned along the way. Today, I'm joined by a fellow thoughtboter, Stephanie Minn.
STEPHANIE: Hi, Joël.
JOËL: Welcome to the show.
STEPHANIE: Thanks. Happy to be here.
JOËL: Stephanie, what's new in your world?
STEPHANIE: Thanks for asking. I've been working on writing a CFP for RubyConf, which you have been plugging internally at thoughtbot. I wasn't really sure if I wanted to do it, and then I found out about RubyConf Mini, which is happening as an alternative to the main conference in Houston. And that got me really excited to have some more options and just got me thinking about what I might have sitting on the back-burner that I might want to give a talk about.
JOËL: That's really exciting. I'm curious, what is your process for coming up with an idea for a talk?
STEPHANIE: I think they come in seasons, ideas, for me, so not even necessarily when it's conference time. But if something has been sticking in my brain for a really long time, especially as it relates to processes on teams that I'm on or my day-to-day workflow, and it's something that I keep coming back to and trying to figure out what it is about it that my brain wants to work through a process, that usually tips me off that this might be something that other people are thinking about or working through.
In this case, I am planning to write a CFP about pair programming. And yeah, it's something that I've been thinking about doing for a while, and it seems kind of an evergreen topic. So I thought I would pull it out for this conference. And if it doesn't end up getting accepted, I can always resubmit again in the future.
JOËL: I love that. So it sounds like you have a note or maybe an actual written notepad somewhere where you just, over the course of the year, build up ideas, and then you take a look at that when conference time comes around.
STEPHANIE: Yeah, that's about it. I have just a very long-running note of half-formed thoughts. And then, when I give myself time to really reflect on how things have been going at work, I usually revisit it, and if any of them still resonate or stand out to me, I will go through and try to see if there's any content to come out of that. What about you? I know you are an extensive note-taker and ideas blogger.
JOËL: I have to say I really like your approach of gathering ideas throughout the year. I've worked with many people who would love to give a talk at a conference as a professional goal but then get stuck in the I don't have any ideas. I don't know what I would talk about. And most people have a thing they could talk about. They just don't know it.
And it sounds like you've done a really great job of gathering this info throughout the year so that when the time does come, you don't just freeze. You're like, no, here are the 10-20 things that I experienced or that I am an expert in or that I would love to share. And maybe there are two or three in there that would be very well-fitted for the conference you're looking at. So I love that idea. I have not done that myself personally, but maybe I should start doing that.
STEPHANIE: What about you, Joël? What's up in your world?
JOËL: So I've also been thinking a lot about RubyConf coming up, working on a few ideas for myself. And then, there are a few people that have reached out to me to help them craft ideas or get a little bit of feedback on their proposal. So I've been doing a lot of proposal reviews as well.
STEPHANIE: What do you enjoy about reviewing other people's proposals?
JOËL: I think for many people speaking at a conference is a really big, ambitious professional goal, and so helping people achieve that is really fulfilling for me. Some people might feel almost inadequate or unprepared. But because I know them, I know they've got good things to share.
And so it's almost seeing the greatness in them that they don't quite see yet or that they don't feel confident about. And so being able to see that in their proposal and say, "Oh, there’s a core of a great idea right here, tweak it a little bit, and that'll give you a slightly better chance with the committee and help you towards that path of being on stage for the first time," is really exciting.
STEPHANIE: I spoke at RubyConf last year, in 2021, virtually. And I remember that was my first time speaking at a conference. And I was worried that my talk was not super hardcore, technical enough. But my goal for my talk was to aim it towards other developers like me who are maybe mid-level and wanting to reach this whole audience of people who are attending these conferences to learn and to level up who aren't necessarily super senior experienced developers.
And it was a really great experience. People seemed to really resonate with that. So I really encourage folks to speak about things that are resonating with them at whatever point in their careers because there are so many people out there who are probably in the same boat and want to hear what you have to say.
JOËL: Absolutely. I'm curious, now that you have experienced the full cycle at least once, from ideas to crafting a submission, to getting accepted, preparing a talk, delivering the talk, and then recovering from that, what are maybe some lessons learned or some things you weren't expecting the first time you went into that that now you do know going into another cycle?
STEPHANIE: Yeah, the power of community; I had a lot of support from WNB.rb, a woman and non-binary Ruby community. We crafted our CFPs together and then practiced our talks together and had a working group that met every couple of weeks to give feedback on our talks as we were working on them. And it was really awesome to have that accountability, to have that support, people to tell you that your talk is good and give you a thumbs-up.
And I really want to continue investing in my community that way. And I really appreciate you asking this question because I guess I do have things I've learned and would want to share that with other people in my community, and yeah, just continue to encourage folks who may not have been traditionally encouraged to speak at conferences.
JOËL: Community is so powerful. Even though I've spoken at multiple conferences, I still get nervous about my talks. I have a lot of self-doubt about whether my topic is good, whether I'm sharing it in a way that's going to be impactful. And I had a magical experience at RailsConf this year where a group of us were at a hotel lobby practicing our talks the night before. And I was just still so unsure about my talk.
And the feedback that I got there gave me a huge boost of confidence that I was able to ride into the next day and give a talk that I think turned out rather well. But honestly, that was my favorite moment of the conference was 11:30 p.m., a group of people in the hotel lobby taking turns practicing their talks.
STEPHANIE: Yeah, I love that.
MID-ROLL AD:
Debugging errors can be a developer’s worst nightmare...but it doesn’t have to be. Airbrake is an award-winning error monitoring, performance, and deployment tracking tool created by developers for developers that can actually help cut your debugging time in half.
So why do developers love Airbrake? It has all of the information that web developers need to monitor their application - including error management, performance insights, and deploy tracking!
Airbrake’s debugging tool catches all of your project errors, intelligently groups them, and points you to the issue in the code so you can quickly fix the bug before customers are impacted.
In addition to stellar error monitoring, Airbrake’s lightweight APM helps developers to track the performance and availability of their application through metrics like HTTP requests, response times, error occurrences, and user satisfaction.
Finally, Airbrake Deploy Tracking helps developers track trends, fix bad deploys, and improve code quality.
Since 2008, Airbrake has been a staple in the Ruby community and has grown to cover all major programming languages. Airbrake seamlessly integrates with your favorite apps to include modern features like single sign-on and SDK-based installation. From testing to production, Airbrake notifiers have your back.
Your time is valuable, so why waste it combing through logs, waiting for user reports, or retrofitting other tools to monitor your application? You literally have nothing to lose. Head on over to airbrake.io/try/bikeshed to create your FREE developer account today!
JOËL: One thing we've been doing recently at thoughtbot is every other week book club discussion, and we've been looking through the book Ruby Science published by thoughtbot. Every week, we'll have someone who is a facilitator, who has done the reading and has prepared some questions for the group. And you recently facilitated a session on the topic of CASE expressions and why they might be a code smell. That sounds like a really controversial statement. How did you approach that topic?
STEPHANIE: It's funny because I was looking at the upcoming chapters to pick a topic to facilitate for this book club, and CASE statements stood out to me because I was like, oh, I know what that is; that will be easy. [laughs] But it turned out to be a bit meatier than I thought it was going to be. I'd say that I didn't really consider them a code smell until I read the chapter of Ruby Science talking about them. So I was a bit surprised because they seem so common, which is probably also why I thought it would be an easy topic.
JOËL: Would you say that reading the book or that particular chapter changed your mind?
STEPHANIE: I think it did only because I hadn't necessarily given them a second thought or thought of them more deeply in that way. I think that, at least in my experience, you encounter CASE expressions pretty early in your career, and you think they're a cool tool for making your conditionals look a bit nicer.
And it takes probably a bit more experience, a little bit more pain using them or trying to extend them that you start to have a bit of a more higher level awareness of what might be problematic about a CASE expression. But the book club that I facilitated, we had a really engaging discussion where most folks agreed that it was a code smell but also said that it depends.
JOËL: Classic consultants.
STEPHANIE: Truly. One thing that someone said that was a really nice takeaway for me was that CASE expressions get a bad rap in object-oriented languages because there are typically other tools or options you can reach for that might be preferred. And someone else said that it's probably a sign that you might be doing too much in the method.
JOËL: Hmm. You mentioned that there are some tools and things that might be preferred over CASE expressions. What are the common alternatives that people say you should use instead of a CASE expression?
STEPHANIE: I think one simple solution that we discussed in the book club for more straightforward cases would be a hash lookup to use instead of checking for equality via CASE statement. Another solution we talked about was polymorphism, which I think might refer back to the idea of having a bit of a higher level understanding of abstractions in the codebase and what things might look like in the future, especially when you might not have too many conditionals yet in your CASE expression.
Another thing that really stuck out to me in our book club discussion was another thoughtboter mentioned Sandi Metz’s 99 Bottles of OOP. And in that initial solution, she presents a CASE statement as the perfectly fine solution for now. And I thought that was really interesting because, in some cases, that might be all we know about the problem, and that is perfectly fine. What do you think about that?
JOËL: I love the idea of starting simple. Don't try to start with abstraction, especially if you're doing test-driven development. You have a test, make it go green, use the simplest thing, use duplication, use all the dirty tricks. And then from there, now that you know I have a test that was red and this code makes it go green, now the question isn't how do I solve the problem? It's how do I improve the solution? So we've kind of separated those two steps out, and I really like that.
STEPHANIE: Yeah, I remember you mentioned that you had refactored something into using a CASE statement. And I'm curious if you want to share more about that.
JOËL: Oh boy, this was a "fun" problem. Fun is in air quotes, by the way. It was a multi-step form, AKA a wizard in a Rails app, where every step submitted to the same controller, and the controller was a huge mess. It had to handle submissions from four or five different forms, some of which shared fields.
And it was this huge, deeply nested conditional thing that checked if this field is present in params, that probably means we're on step three, except if this other field is also present, then it probably means we're on step four. But if this Boolean flag in the database is set to false, we might be on a variation of step three. And because there was branching, potentially, it was an absolute mess. By looking at the code, you could never know what step of the processing you were on.
What I did is instead of all of these nested if else conditions, I wrote a flat CASE expression that just said, if step one, do step one logic or process step one form. If step two, process step two form and so on. So it was nice and flat. I was able to reuse some parts of the work across by making private methods or other objects, things like that.
But you could easily tell in any part of the code what step you were processing. Which means if you get a new feature from the client that says, "Can you modify the behavior on step four?" Now you actually know where to go to. You go to this controller; you find the big CASE expression. You find the branch that says, "If step four," and then you drill down from there.
STEPHANIE: So after refactoring that into a flat structure, did you find the code more readable? Did other folks on the project think so too?
JOËL: Yes, it was unanimously loved because this is the part of the code that everybody feared to touch. It was the most awful, gnarliest code. And a few of us had touched it, and so if you did the git blame, our names would show up, which meant that anytime anybody got stuck in that code, they would reach out to us and say, "Hey, you're the last one who touched it. Can you fix this for me?" And it was a big game of not it. Cleaning it up made this code accessible to everybody on the team.
STEPHANIE: And why do you think a CASE statement was the right solution in this particular case?
JOËL: I think if it's a multi-step form that maybe had seven steps in it, you clearly have seven branches that you're working with. And so hiding that behind nested conditions where you try to reuse each other's branches just muddied the waters. We have a seven-way branching path; let's be honest about it upfront and do a seven-way CASE expression.
STEPHANIE: One thing that we didn't really talk about as much in our book club discussion was that CASE statements can be quite readable, especially for newer developers. And even though we all did think it was a bit of a code smell, I recently encountered on my client project in a code review someone saying that they preferred a CASE statement in that situation because it was easier for them to grok. I think that's a benefit worth considering before trying to do something fancier in some cases. And I'm curious what you think about that.
JOËL: I strongly agree that a CASE expression is a great place to start, especially when you have actually more than two branches. Your logic could go one of n ways. I generally like to branch earlier than later in a lot of code. It's better in my mind to have a seven-way branch at the top of your decision tree and then just straight lines down than this constantly looping back and branching again and looping back, trying to force everything down a single path when it really doesn't want to be.
STEPHANIE: So, in this case, did you know that you had those seven branching paths upfront, or did you have to tease that out?
JOËL: I did not know from the code. Honestly, it would be very difficult to infer that from the code. But from the product, I knew this is a multi-step form with seven steps. And so I knew what the branches were from the product description. But no, it was almost impossible to infer that from the code.
Long-time listeners of The Bike Shed may remember an older episode where Steph and Chris discussed multi-step forms and how best to approach them in Rails and also in JavaScript. And one thing that did come up is that an ideal way to work with a multi-step form in Rails is to have every step be its own controller. So you have a view, it submits to a controller, which renders another view or redirects to another view which submits to another controller. And that is the direction that we went with this multi-step form eventually.
Once the single controller had a big CASE expression in it, we slowly started moving each branch out to its own controller. And now we had the step one controller, the step two controller, the step three controller, and so on. And I think that was probably the best solution in the end. But we had to go through the CASE expression just to know what was safe to move out.
Interestingly, this refactor is effectively replacing a conditional with polymorphism because all of our controllers are controller objects. They respond to the same interface. And so this gets classic refactor that Ruby Science suggests, which is what we did and kind of what Steph and Chris recommended if you had the luxury of starting from scratch all those episodes ago.
STEPHANIE: Nice, I'm glad it turned out that way and was a lot more manageable.
JOËL: It's really interesting when you're working with a situation like that where you've got really messy code, and you can make some improvements. And it's like, how far do you go? Especially because there's usually a backlog of new features that the customer wants you to implement.
So I'm curious for you, Stephanie, how do you know when you've gone far enough in improving code, either in a refactor step for your own code for a feature you're writing or maybe you're trying to take a break and say I'm going to take a little bit of time today to improve this area of the code. How do you know how good is good enough?
STEPHANIE: That's an interesting question. I think I encounter that in a couple of ways, either in my own work when I am tasked with a feature, and I start getting into the code, and it stresses me out and leaves me a bit confused and not sure where to go to work on my feature. That is usually a signal that I might need to pay some attention first and make the change easy and then making the easy change.
The other common thing that I have experienced on teams is we collectively feel the pain of an area of the codebase. And maybe we talk about it at a developer meeting, and all agree that, yeah, we really want to give this part of the code some love and add it to the backlog. But it's tough in that case because, like you said, there are a lot of new features that stakeholders want. And we as developers want to be over here taking care of our little codebase [laughs], making sure that it is healthy and it feels good to work with.
JOËL: I feel like I don't just want my codebase healthy; I want it pristine.
STEPHANIE: Ooh, pristine. What does that mean to you?
JOËL: I want it perfect, nice, and shiny. And, of course, it's never that, which is why it's always tempting to toss out the old code and start over and do it right this time. That's not a good thing. You have to be able to live with the messiness of everyday life and the fact that, okay, here's an idea. I think if your codebase is perfect, you've put too much work into it. You've gone too far, and you're beyond that; when is good enough good enough?
STEPHANIE: Whoa, that's a big statement.
JOËL: [laughs] Feel free to disagree with me here.
STEPHANIE: I guess I'm curious what perfect is in this case.
JOËL: I think it's subjective for the developers who are writing it. But oftentimes, the ones who are looking for perfection go way too far in their quest for that.
STEPHANIE: Way too far at the expense of things like business value or other things?
JOËL: I think in two ways; one, you probably ended up overengineering things to try to make it so perfect. Your design needs to have some amount of flex in it for the unknown. It's okay to have some rough corners because it's going to change. And you're going to have to redo that corner next week anyway. So you need to not go all the way in making everything absolutely perfect.
The other thing is that if you are putting in the effort to make everything perfect, at some point, you hit diminishing returns. And that's not worth your time from a business perspective or even on a personal project where you're just trying to ship things. At some point, you need to make actual progress.
STEPHANIE: I'm curious if you mainly hold yourself to those very high standards or if you also think about that when reviewing other people's code.
JOËL: So I mentioned earlier that I want my code to be pristine. I want to be clear, that's a bad thing. I do not actually hold myself to that standard. And I try not to hold other people to that standard, either. It's sort of tempering idealism with pragmatism. So being able to say, look, can we cut scope and focus on just one thing? Or does this fulfill the need that we have? And will it hurt us if we leave it like this and come back to it later? Or that question I asked you at the beginning, is this good enough? And maybe we can come back to it eventually.
STEPHANIE: I really struggle with that question sometimes because, in some ways, people talk about software as a craft. And if we were building it in a vacuum, we could fine-tune and hone it until it's this beautiful, perfect, pristine thing. But because we write software for real things in the real world, we are constrained by the needs of our users, or the business, or just the purpose of building software is for folks to use it. And in that case, part of the job is evaluating trade-offs and deciding when is good enough.
But sometimes, when I'm by myself working or coding for a little while, I do get sucked into wanting to make this the best that it could be just for my own personal fulfillment and joy. And I have to pull myself out of it sometimes and take a step back and be like, is this good enough for now, good enough for other people to be able to understand, work with in the future? And sometimes, it also requires getting other people's input too.
JOËL: That's really valuable.
STEPHANIE: Yeah, the worst thing that could happen is squirreling away with your code, and then you emerge with something that was totally not what was asked for. [laughs]
JOËL: Especially on a work project. On a personal project, it's often good to know why you're doing a thing. And so maybe you want to see how far you can get away with pushing a particular metric, whether it's you want to go extreme on the decoupling or 100% TDD, or maybe you want to try something like test && commit || revert which is a development methodology. And those are all great as learning experiments, and then you go as deep as you want.
I'm going to make another hot take here, and again, feel free to tell me I'm wrong. I'm going to say that on your own personal projects, if you pursue perfection, even when it's not for work, pursuing perfection on personal projects dooms them to join the others on the pile of uncompleted projects on your GitHub.
STEPHANIE: That is an interesting take. I think it depends on the goal of your personal project because I personally like to have my projects be a bit of a sandbox, and I have no expectations that they will end up being anything that other people would necessarily look at, even though I guess they just end up public on my GitHub and are just sitting there in a weird, unfinished state.
But yeah, I like to use them as an opportunity to, like you said, practice those concepts that I am really excited to explore but might not necessarily have the opportunity to on whatever client project I'm currently working on. And sometimes, I end up just scrapping it, but the exercise itself was valuable for me. I'm curious, though, what types of personal projects you have that lead you to have that opinion.
JOËL: I think the way I use personal projects is very similar to you in that they're generally for my own personal growth and entertainment. It's about the journey, not the destination. So I generally have no intention of making this a thing that other people will use. It's typically a way to try out a technique, or a concept, or an idea. And so, for those, going really far on a performance or quality metric can be the goal. And that's completely okay with the knowledge that I probably will not complete or ship this project.
I've done a few others where I've done the opposite. I've joined Game Jam events where you typically have a hard deadline. This could be a longer one, like maybe a month or as short as a day or a weekend, and you have to build and ship something within that deadline. And then you have to really make some pragmatic choices.
STEPHANIE: Yeah, that sounds like a lot of pressure. I don't know if I would necessarily thrive in that kind of environment. I really like to spend a lot of time thinking about my code and looking over it again, sometimes to the point where I might be a little bit too precious about it.
I was reflecting on this recently, and I thought about back when I was earlier in my career and didn't have any idea of what clean or good code was or looked like. And I would just write the code that would make my future work and just put it up for review. And I was very blissfully naive, I think, at that point in my career where I wasn't self-conscious about it in any way.
And I think I'm trying to find a good middle ground between being comfortable with whatever comes out when I do some work or write some code while also having more knowledge and experience being able to revisit it and give it a deeper look after some space and feeling good about it without spending too much precious time on it.
JOËL: Yeah, it's that classic consulting; it depends. Learn to balance code quality idealism versus the pragmatic reality of your goal, which is I want to ship something, both on your personal project and at work. That perfect code is useless if you can't ship it for contexts where you actually care about shipping.
And on that note, let's wrap up. The show notes for this episode can be found at bikeshed.fm. This show is produced and edited by Mandy Moore.
If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review in iTunes. It really helps other folks find the show.
If you have any feedback, you can reach us at @_bikeshed or reach me at @joelquen on Twitter or at hosts@bikeshed.fm via email. Thank you so much for listening to The Bike Shed, and we'll see you next week. Byeeeeeee!!!!!
ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.Sponsored By:Airbrake: Deploy fearlessly and fix bugs faster with Airbrake Error & Performance Monitoring. Airbrake notifiers are available for all major programming languages and frameworks, and install in minutes, with an open-source SDK-based install and near-zero technical debt. Spend less time tracking down bugs and more time developing. Visit Frictionless error monitoring and performance insight for your app stack.Support The Bike Shed

Aug 23, 2022 • 37min
351: Learning in Public
It's Joël's first episode as host of The Bike Shed! 👋
Joël has fellow thoughtbotter Steve Polito join him to talk about the benefits and drawbacks of "learning in public" and how there are many, many different ways to do it.
This episode is brought to you by Airbrake. Visit Frictionless error monitoring and performance insight for your app stack.
Transcript:
JOËL: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot. I'm Joël Quenneville. And I'm joined today by fellow thoughtboter, Steve Polito.
STEVE: Hey, Joël. Thanks for having me; excited to be here. And congrats again on the new hosting gig.
JOËL: It's exciting to record with my first guest, and I'm excited that you get to be a part of this. And together, Steve and I are here to share a little bit of what we've learned along the way. So, Steve, what's new in your world?
STEVE: Well, on the professional side of things, I've been working on a Rails backend application that connects to a React frontend. And specifically, it's in the healthcare space. My biggest, I guess, struggle but also [laughs] thing that I've learned the most from this project is working with an inconsistent API can be very challenging. And that's been the consistent theme with this project.
But from that, I'm learning a lot. Because prior to this, I'd done a lot of work with just traditional CRUD apps where it's just all-encompassed in the Rails application. So you're kind of in control of everything. This is my first time where we're very much dependent on a third-party API. I'm learning a lot, but it can be challenging at times. But we've gotten in a space now where it's a lot more predictable, and therefore, working with it is easier. That's on the professional side of things.
Personal side of things, I, for whatever reason, decided to run a marathon in September, which means all of the training has to happen in the heat of the summer. I live in New England, and it's been unbearably hot the past two or three weeks, which means training has been unbearable. [laughs]
JOËL: Ouch.
STEVE: Well, I mean, that's what I get for signing up for a marathon at the end of the summer. So I look forward to just working with the unreliable API versus [laughs] doing this right now. That's what's going on with me. What's going on in your world, Joël?
JOËL: For long-time listeners of the podcast, they'll know that former host, Steph Viccari, has been working on a slow test suite. And part of that work has been converting some old Test::Unit tests over to RSpec. I've been working on the same project with her, and so the saga continues.
One of the really frustrating aspects of this work has been the Test::Unit tests rely a lot on fixtures which are just full of mystery guests. The fixtures that are just loaded at the top of the file refer to a few thousand records in the database, most of which are not relevant to the test that I'm trying to convert over.
The problem is that I don't know which ten records, you know, which two users out of the 100 defined in the fixture file are relevant. They're not referenced directly anywhere in the test. But if the RSpec conversion that I do fails, it will break because some user is not present in the database. And so I need to reverse engineer the code and figure out what is missing, which user record is just assumed to be in the database.
STEVE: Yeah, that sounds frustrating. Honestly, until working at thoughtbot, I didn't quite understand the concept of mystery guest. Because when I learned Rails, I just did the Michael Hartl Rails Tutorial, which, in an effort to make it as easy as possible, he just kind of does vanilla Rails. So there's no Factory Bot or RSpec, for example, and it's all fixtures. And it works very well for teaching you how to build and test an application without getting bogged down with too many of the extra things that come along with that.
So I always thought, okay, fixtures, cool, no big deal. Why does everyone always use Factory Bot?[laughs] Like, what problem is this solving? And I'm realizing now because I've run into this too, the issue that it’s solving is this mystery guest, so that's one of the issues that it's solving. And that's just one of those things that I didn't really appreciate until I would run up against it in a similar situation you're describing now where you're writing a test. It might even be a very simple test, right? Like five lines or something, and you're just expecting something trivial to happen.
And it's failing, and it's failing for the wrong reason. The message is so cryptic. And you're just like, what is this thing talking about? It's like referencing something that has nothing to do with the test. And that pain right there is the pain of a mystery guest. I just didn't have a name for it until listening to these episodes. And now I can appreciate why you want to avoid that type of stuff and also why Factory Bot is helpful for that.
JOËL: I think it's the kind of pain that tends to bite you more when you're modifying the tests later on than when you're writing them upfront. And since now, with the work that I'm currently doing, it's all modifying existing tests, I'm feeling this pain on a daily basis. Does that track with your experience as well?
STEVE: Yeah, pretty much. And then what ends up happening is you're working on a feature, and the test fails for the wrong reason. And then you realize 30 other tests fail for the wrong reason. And then, before you know it, you've spent four hours going down a rabbit hole to clean up the fixtures, or the mystery guests, or the implied setup that might be shared across other tests. It's just such a momentum killer, first of all.
You're in this headspace of like, okay, here's the feature I'm working on. Let's just bang this out real quick; no big deal. I want to go to lunch in a couple of minutes. [laughs] And then you're trying to fix this test because it's failing for the wrong reason. And then you keep pulling the string, and you're like, oh, okay, well, there must be a mystery guest or something, but that took like 20 minutes to figure out.
And then you figure that part out but then maybe fixing that mystery guest involves either updating that particular fixture, which could then fan out and cause other tests to fail because it depended on that fixture to have certain properties. Or you have to create a new fixture. But if you create a new fixture, there's now an extra record in the database. And that could break other tests because they are maybe expecting there to be a certain set of users and other things.
But that's just one of those things that early on, I would listen to episodes like this or hear about mystery guests, and I would be like, I just don't get what they're talking about. If you have a few fixtures, how is that so hard to keep straight in your head? And sure, at first, it's not a big deal if you have maybe two fixtures or something.
But then it quickly just reaches an inflection point where either there's more than one person on your team, or you have to add more fixtures or whatever. And then it just reaches an inflection point where it's just not sustainable anymore. And that sounds like that's obviously the point at which this project is at, and that's where you're trying to rein it back in.
JOËL: Yes. So it's definitely making the conversion from Test::Unit over to RSpec more difficult. I've been trying something a little bit clever to try to figure out what data is actually needed because that's my core problem. I have a Test::Unit test that doesn't define any initial setup data. It just assumes that data has been created by fixtures at some point. But there are thousands of records in the database. So which ones do I need to port over to this setup phase of my RSpec test?
What I've been doing is hooking into Active Support notification and watching the records that get read from the database from the Test::Unit tests. And that can tell me, oh, it's these ten that this particular test is using. Those are the ones you're going to need to convert over to your setup block.
STEVE: That's clever. I like that. So you were just looking at the logs essentially. Or did you have to do any puts statements or anything? Or was it just the default internal logging mechanism that Rails has under the hood?
JOËL: The simple version of this would be to look at the logs, so tail the test log file. I'm trying to be a little bit fancier and hooking into Active Support notification, which is something built into Rails that allows you to just listen to certain events in the system and then do actions based off those events. So I can subscribe to any database read and then say call this block when a database read happens. And in that block, I can then update a stats object that, over the course of the test, will then tell me what objects have been read from the database.
STEVE: Oh, okay. That's clever. I'm glad you shared that too. Based on this discussion of mystery guests, I feel like that's just a good use for that tool. I almost wonder if there's an opportunity not even to abstract that because that'd be too much work and overkill, but just, I don't know, make like a gist or something and just reference that for the future.
Because I feel like this is the type of thing that other people are going to run up against...or maybe even a blog post or something because it's just like, if nothing else, it would be good for future Joël to be like, how did I do that again? Oh, yeah, here it is. Like, it's in this blog post I wrote six months ago. So I could just copy and paste the code snippet and call it a day.
JOËL: It's funny you mention blog posts because we have a lot of these conversations internally at thoughtbot. And without fail, someone will eventually comment, "This is great content. You should turn it into a blog post," to the point where we now have an emoji reaction for you should make this into a blog post.
STEVE: Right. That's what's really maybe special about the software industry is there's just a lot of knowledge share built into it just with open-source software, for example. I mean, that's already a form of knowledge share. It's not a blog post, but it's a form of knowledge share. And I just think getting into a habit of just sharing these little artifacts, big or small, whether it's a blog post or just a code snippet, is really helpful for a variety of reasons.
But one, and in this case, to go back to the issue that you've been facing on the client work is you just explained...We talked about a lot of things; two of them were like, what's the mystery guest? That's helpful for some people to know because until very recently like I said, I didn't even really understand what the pains of mystery guests were. And then, we also talked about a potential solution to that.
So a naive approach is tailing the logs, but then you took it a step further with that clever solution to use that notification object. And if we weren't recording this right now, that might be lost in the ether forever. Maybe the people you're working with on your team would know about it, but that would kind of be it. So I think there's an opportunity for you to maybe abstract that into like a code snippet or blog post or something and just store it away for later so that future Joël or another developer can learn from that.
JOËL: That's a really good point, Steve. Creating public artifacts like that is a form of...I've heard it referred to as learning in public before. And that's actually a topic that I think you've really demonstrated mastery of. You are great at sharing the things you've learned or even the questions you have with your colleagues, and the team at thoughtbot, and the broader developer community. What was your journey into starting to share in public like this? Because I know it can be really intimidating, especially for someone who's early in their career.
STEVE: Yeah, that's a good question. So a very brief background on my career history is I'm not classically trained, so to speak, and I'm doing air quotes for those listening. When I say, I'm not classically trained, what I mean is I went to school for graphic design. And there was some overlap with web design, obviously.
But I ended my collegiate career really just knowing how to use Dreamweaver and knowing a little bit about HTML and CSS and barely anything about JavaScript, and I didn't know anything about server-side languages. That was my base. And I was fortunate enough to get a job at a small WordPress agency. I got really good at understanding WordPress and how to configure a website and then making it look like the Photoshop document.
JOËL: There's a shocking amount of the web that runs on WordPress.
STEVE: It's a huge amount. And what's nice is that it doesn't...as you just heard, I didn't have a lot of experience with making production websites. So WordPress made it easy enough for me to get my feet wet. But I would run into a lot of problems. And I was the only developer at this agency, so I couldn't turn to my co-worker and say, "Hey, can you take a look at this real quick?" It was just me and Stack Overflow. That was it.
The reason I'm saying this is because Stack Overflow and being the only person at the agency forced me to learn in public but from a different mindset. I wasn't necessarily learning in public; I was desperately trying to solve a problem by the end of the day. And it just happened to be in public because I would have to either go on Google or Stack Overflow or forums to find the answer.
JOËL: So were you asking questions on these sites then? Like, you were going into a chat room and asking questions or going to Stack Overflow and asking questions.
STEVE: Yeah. If I couldn't find a solution quickly, I would just go on there and just shamelessly ask questions which they were, in some sense, naive questions. Looking back at them now, it clearly highlighted that I didn't understand the fundamentals, but that's okay because I know I didn't. [laughs] And I'm sharing that with everyone right now, so it's not like it's a secret. Because that was the only way I was going to figure it out, like I said. And I didn't have anyone at that agency to ask for help.
So that got me into the mindset of just ask for help. But it also got me into a mindset of...one thing was, okay, I can't just paste the entire error message, like, the entire 3,000-line error message from the logs onto Stack Overflow. That's not going to help anybody. No one's going to answer that question. I needed to start to get good at distilling down the problem into its smallest part to then be able to share it, so I would at least incentivize someone to answer it versus pushing them away because who wants to read a non-formatted log file dump?
JOËL: That is a skill in and of itself.
STEVE: Yeah. I mean, it took time, don't get me wrong. And at first, I was posting those [laughs] giant log files. I would just say, "Hey, can you help me?" [laughs] And it's like, there's no context, and it's just 3,000 lines of gibberish. So obviously, I quickly learned, well, I got to make these bite-size. But then, from there, I slowly learned over time thanks to the community, and just the advent of the internet, and searching and everything like that.
But then I got to a point where I was confident enough with the skills I was learning that I wanted to start giving back and if nothing else, it was really just to help future Steve. So when I would run into an issue that I couldn't solve, typically at this point, it was like WordPress or Drupal issues. Once I was able to solve it, I would then write up a blog post with that solution, and they were very simple posts.
And just by chance, they happened to be very search-engine friendly because I would just, like, the title of the post would be basically the error message or how to do X in Drupal. Obviously, as a software developer, no shortage of problems, right? Like, every day, you're going to run into something that you actually just do not know the answer to. So I would just amass dozens of these problems. And if I found one interesting enough, I would post about it. And I just got into a habit of that because, like I said, if nothing else, it helps me for the future.
But then it's also nice to know there's certainly going to be someone else out there who has the same issue. And it's kind of exciting to think someone on the other side of the globe is going to possibly search this thing and maybe land on my website or something, just like I have done countless times where I've put in something into a search engine, and I land on someone's website, typically the thoughtbot website, [laughs] and I read the solution there. So it's exciting to be part of that.
JOËL: Were you ever afraid that somebody else would come along and tell you your solution is wrong?
STEVE: I wasn't necessarily afraid because that comes with the territory. Honestly, fortunately, I've never really had a situation where someone was outright mean or disrespectful. For the most part, I find folks are very helpful. But it does help like I said, if you distill those questions down and make it simple for someone to help you with. But yeah, I mean, that is one of the...I don't want to say risks, but that comes with the territory of learning in public, which is you might face criticism.
MID-ROLL AD:
Debugging errors can be a developer’s worst nightmare...but it doesn’t have to be. Airbrake is an award-winning error monitoring, performance, and deployment tracking tool created by developers for developers that can actually help cut your debugging time in half.
So why do developers love Airbrake? It has all of the information that web developers need to monitor their application - including error management, performance insights, and deploy tracking!
Airbrake’s debugging tool catches all of your project errors, intelligently groups them, and points you to the issue in the code so you can quickly fix the bug before customers are impacted.
In addition to stellar error monitoring, Airbrake’s lightweight APM helps developers to track the performance and availability of their application through metrics like HTTP requests, response times, error occurrences, and user satisfaction.
Finally, Airbrake Deploy Tracking helps developers track trends, fix bad deploys, and improve code quality.
Since 2008, Airbrake has been a staple in the Ruby community and has grown to cover all major programming languages. Airbrake seamlessly integrates with your favorite apps to include modern features like single sign-on and SDK-based installation. From testing to production, Airbrake notifiers have your back.
Your time is valuable, so why waste it combing through logs, waiting for user reports, or retrofitting other tools to monitor your application? You literally have nothing to lose. Head on over to airbrake.io/try/bikeshed to create your FREE developer account today!
JOËL: One thing that I really appreciate with some of the things that you share on social media is kind of like what we say here on the show, sharing a little bit of what we've learned along the way. So you get to follow Steve's journey. And it's like, I'm trying this problem; here is the solution I have so far. It seems to solve some problems, not everything. Tune in tomorrow to hear how the problem keeps developing.
STEVE: Yeah, exactly. That's kind of why I try to make sure I'm giving back at least half as much as I'm taking, so to speak. So in these transactions, like on social media, I'm stumped on something or maybe not even stumped, but I'm just, like you said, exploring an idea. And I want to have it peer-reviewed, so to speak. I mean, in some ways, some of these things are almost like a Twitter code review, right? It's just like, instead of having the formality of doing it on GitHub or whatever, it's just like, here's a snippet, quick gut check here.
And then what's nice is that people are nice enough to respond with what they think. They'll reference other posts or other projects that might touch upon that. And what's nice and what I hope is happening with these exchanges is maybe someone learned a little something about what I just posted. Because I know that I'm certainly learning something from the feedback I get.
And then again, it's almost like code review. You get this nice history of what this idea is about and then different stances on it. And then it just sort of serves as a little bit of a learning tool right there. And then yeah, I'll try to follow up later on, like, hey, here's where I landed now. But maybe it's a little more fleshed out.
JOËL: What are maybe some drawbacks of this concept of learning in public? Are there some reasons you might not want to or not be able to do this?
STEVE: I do think there are...maybe not drawbacks, maybe just risks. An obvious one I can think of is if you're working on proprietary software; for example, you legally probably can't share anything that you're working on. So that makes it challenging because you can't just straight up take a screenshot of your editor [chuckles] and be like, "Hey, look at this cool thing I'm working on today."
That adds a little bit of a roadblock because then you probably have to simplify it or, I don't know, anonymize it in a way that it's just generic. So it just adds a little bit of extra work. But in some ways, that might actually be a good thing because then you've simplified the problem to its purest form, so to speak.
Another drawback we kind of touched upon is you're opening yourself up to criticism, that can be a challenge. Everyone communicates differently. People may not want to use Twitter, for example, to learn in public. They might just want to have a personal blog and do it that way.
JOËL: Turn off the comments.
STEVE: Exactly. Turn off the comments. If you're someone that is hesitant of criticism or just being on social media in general and all that, learning in public can be whatever you want it to be. So what I mean by that is we talked about Twitter and social media. That's kind of an obvious way to learn in public. But another way is you could just have some GitHub repos or your own personal blog, you know, things like that.
What's being implied here is learning in public means, like, public, anyone could access it. But I want to challenge that because public could mean different things in different contexts. So at thoughtbot, for example, we have our dev channel, and people post there all the time. And that's public in a sense, but it's not public to the world. So it's a little more controlled. You know that you're going to get helpful feedback. It's a safe space to do that.
So I would encourage folks listening now that work in an agency or just work in software development in general see if you can create your own dev channel at work or something like that if you don't already have something like that because that's a good way to, I guess, encourage people to learn in public.
JOËL: I love that you're redefining public a little bit here and the idea that public could just mean your team at work or your company. That's a concept that I really like because now maybe it's a little bit less intense to share with them. And it can be something as simple as today I learned. It could be a question about a particular technical thing, or here's the thing I did; it works. Is there a better way to do it?
STEVE: Exactly. If you think about it, code review is a form of learning in public that's built into our day-to-day job because it encompasses a lot of these things. You have to be...I don't want to say ready to take criticism, but it's very common to open up a PR, and you're going to get feedback on it.
The reason I'm hesitant to say criticism is there's a connotation of just criticize me and the person is being rude or something; I don't mean that. I just mean someone who is being critical of your work in the sense that they're making sure it meets the requirement. And it is quote, unquote "good code" given the constraints. So you have to open yourself up to criticism that way.
You're also creating these little artifacts because, in code review, there's going to be a back and forth. Someone might suggest a change; someone else might praise or just give you a shout-out to be like, "Hey, I've never seen this before. I've never seen this method before or this pattern before. This is really neat. It reminds me of something I learned over here." And they might paste a link to something else.
So yeah, code review is a form of learning in public. It's like a very controlled, simplified version of that. And it can also be a good source for learning in public through social media. Because then from that, you get this distilled concept that you can then share to the world or just at work with other people that may not be on your team.
JOËL: thoughtbot has a few, I think, different cultural things that we like to do that all converge on some of these ideas, one being that we have dedicated investment time to try to improve ourselves. Two being that we try to share anything that we create as publicly as possible. So default to making something publicly available unless there's a good reason to keep it private which is the opposite of a lot of companies.
And then finally, bringing that all together, trying to, in the things that we learn, in the work that we do, pull out shareable artifacts. So if you're reading a book, if you're working on a project, is there something tangible you can pull out of it to share back with the team or even the broader world? And that might just be dropping, "Today I learned this," in our dev channel. It might be putting up a little proof of concept repo and publishing it publicly. It might be, as you mentioned earlier, writing a blog post about a cool technique that you found helpful on a project.
So we're constantly trying to find ways to take anything that we've learned and not just make it a personal thing but also try to sort of multiply that to, at the very least, our team but where it makes sense also the broader dev community.
STEVE: Yeah, exactly. I don't know about you, but I feel like there are a lot of similarities with learning in public in their many forms with open-source software. Because open-source software is basically learning in public, right? For folks listening who might be hesitant to start getting in the habit of this, I would just encourage you to look at any popular repository and look at all the open issues.
And what I mean by that is these popular repositories that are used by millions of people they're not perfect. Like, they didn't get it right on their first try. And you can read the source code and you can see everything about it. And it kind of embodies learning in public in that way. So it opens itself up for criticism but also praise. And then it's also just a resource there where you can learn from it.
There are so many times where I'll open up the Rails, like, I'll just go to the Rails source code, not because I need to but because I'm curious, like, how do they do that particular thing? Like, the other day, we were working on something where we had an object or a class, and we wanted it to have two class methods, one called perform, and one called perform with an exclamation point. The details of that don't matter, but I was just kind of like, well, that reminds me of Rails with destroy and destroy with an exclamation point.
And I just want to see how do they do that under the hood? Like, not every single detail, but just how does the destroy method with the exclamation point, like, does the call destroy under the hood? What does it do? And I was just like, well, let's just see what Rails does. And we can kind of copy that pattern for what we're doing over here, which was great. And, again, that wouldn't have happened if we didn't have open-source software, which, again, I think is a form of collective learning in public. It's like, it's the source. It's a result of many people working on it.
JOËL: Even for projects that have only a single author, I think there can be a lot of value there. Long-time listeners of the show will know that I'm a big fan of the Elm programming language. And I've participated in a few Game Jam events where you have a deadline, typically a few days or maybe a month, to create a game based on a theme. And I've built some games using Elm. Later on, people will ask me about particular patterns that can be used in Elm, maybe related to games, maybe not related to games.
And I've been able to link them to parts of that open-source code for the games that I built, which are built under pressure. They're not always great quality. But I can link to a particular section of the code and say, "Here's the pattern we were talking about." And that can spin off a whole conversation.
STEVE: Yeah, that's just one of the many advantages to doing these things. And I should also say, too, you say that I'm good at learning in public, but the same goes for you too. I mean, you're constantly sharing things in the dev channel, writing posts. I want to recognize that too because I think that's a skill that you've also mastered. So I appreciate that.
JOËL: Thank you.
STEVE: You share as much as you do, especially because you have significantly more experience than me. So again, to circle back to the mystery guests, I would hear you talking about mystery guests. I've heard other experienced devs talk about it. But a year or two ago, I'm like, I trust these people. Like, I really trust them. They're smart. They're credible. They have more experience. But I just don't really get what the problem is because I haven't actually experienced it firsthand, but I at least knew to be aware of it. And it was in my back pocket, and I could take it out when I was ready to do a deep dive on that.
So if it weren't for things like this podcast or blog posts or other things like that, I feel like the dev community wouldn't be nearly as...it just wouldn't be at the level that it is now. And I don't mean necessarily even Rails; I just mean software development in general. Imagine if all programmers just worked in isolation and couldn't use information from other developers or imagine that in any career, right? Physicians...imagine if they couldn't do knowledge share.
So I just think being in the software industry, it's just easier to share what you're doing because we make the internet in a way. So it's like, we're already on the internet all day, so we might as well just sprinkle in what we're learning.
JOËL: I have a personal note in my notes. It says that the best knowledge is created in the connections between people. So if you're imagining a graph where people are nodes, and the connections between them are edges, all the best ideas are on those edges where interactions happen between people and not just solo geniuses.
STEVE: Exactly, exactly. I like that.
JOËL: Power of collaboration.
STEVE: Right. It's like a neural network or something. It's just like, everything coming together, passing knowledge along.
JOËL: So, Steve, we've talked about how learning in public can be really good for your own personal growth and learning. Are there any other advantages to this approach to work where you're learning in public?
STEVE: Yes, absolutely. I think learning in public is very beneficial for junior devs in particular. And there are a few reasons I think that one of which is I think it helps you stand out amongst other candidates that are applying for a job. I think that just because...if you're constantly sharing what you learn and what you know, and again, these can be very small things. I'm not talking about multi-part blog posts or something. I'm just talking about sharing simple code snippets but just being kind of consistent about it.
Doing that really helps hiring managers to get a sense for how you think, and how you communicate, and how you code because those are all very important aspects of software development. Like, it's not just coding. If it was just coding, I don't know, GitHub Copilot, that would be it, right? We could all just [laughs] pack up our bags and head home. But there's so much more. There's so much more communicating that is involved in the job.
And if you're constantly sharing what you learn, that just makes it easier for maybe a hiring manager or someone to get a sense of how you think, how you code, how you problem solve, and again, how you communicate too because maybe you'll face some criticism like in the comment section or something. I'm not saying that's justified, but also, maybe that's an opportunity to practice your communication skills and maybe ask that person, like, hey, how would you solve this problem? Or, what do you recommend?
Because again, to go back to code review, that back and forth, that exchange that happens every single day. And I just think that if you're learning in public, it's just going to make it that much more easy for someone to get a sense of what you're like before they've even met you.
JOËL: And I think it's a really virtuous cycle here because you mentioned how this is a great way to show your work for potential employers, but at the same time, it's a great way to practice that work. You're talking about how this will help you improve your communication. But at the same time, it's also proving to everyone that you are good at communicating or that you have grown a lot in your communication.
STEVE: Exactly. Yep, exactly. If you're consistent about it, too, you could just scroll through your old blog posts and see what was I talking about three years ago? Versus what am I talking about now? And hopefully, there'll be some improvement and more depth to the articles. And again, it's just a great way to let folks know how you think and how you solve problems.
JOËL: I found that it's not just valuable for junior developers. I think it can be really helpful throughout your career to have public artifacts to point to. I've found that for some of my clients, being able to point back to blog posts I've written, or even conference talks I've given helps build trust, helps to build credibility for some of the work that I'm trying to do.
STEVE: Exactly, yep. And what's really exciting about it is in that moment, when you send that link or send an artifact, that transaction took two seconds. But it just embodies so much of that credibility because it took you years to get all that knowledge. But now, it's just foundational. You have this big foundation of artifacts that you can share. I think that's just wonderful.
JOËL: Keep learning in public. You're building an archive of valuable resources that will just keep compounding in value over the course of your career.
STEVE: Exactly. That's a good way to put it. I like that.
JOËL: Well, Steve, thanks so much for joining us on the show to talk about learning in public. If people are curious to see some examples of how you do this, where can they find you online?
STEVE: If you just search Steve Polito Design, you'll find me, which is kind of a callback to when I was studying graphic design back in college. So that's the best way to find me.
JOËL: So this is a handle on multiple different social media sites?
STEVE: Yep, exactly.
JOËL: Excellent. We'll make sure to link a few of those in the show notes as well. Thank you so much, Steve, for joining us this week to talk about learning in public. Do you have any last words you'd like to share with our audience?
STEVE: Yeah, I just want to thank you, again, for having me on the show. Just for context, a lot of what I learned about software development came from The Bike Shed, so, again, plus-one for learning in public. It helps other people. So it's very exciting to actually be on the other side of the show right now as a guest. So thank you very much. And congrats again on the new hosting gig; so you'll be learning in public too now, so this is great. [laughs]
JOËL: The show notes for this episode can be found at bikeshed.fm. This show is produced and edited by Mandy Moore.
If you enjoyed listening, one really easy way to support the show is to leave a quick rating or even a review in iTunes. It really helps other folks find the show.
If you have any feedback, you can reach us at @_bikeshed or reach me @joelquen on Twitter or at hosts@bikeshed.fm via email. Thank you so much for listening to The Bike Shed, and we'll see you next week. Byeeeee!!!
ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.Sponsored By:Airbrake: Deploy fearlessly and fix bugs faster with Airbrake Error & Performance Monitoring. Airbrake notifiers are available for all major programming languages and frameworks, and install in minutes, with an open-source SDK-based install and near-zero technical debt. Spend less time tracking down bugs and more time developing. Visit Frictionless error monitoring and performance insight for your app stack.Support The Bike Shed

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

Aug 9, 2022 • 40min
349: Unpopular Opinions
Steph and Chris announce Joël Quenneville as the new host of the show! 🎉 Joël talks about his grand plans for where The Bike Shed is going to go from here. (Okay, maybe not grand plans...!)
Together, the group chats about unpopular opinions and hot programming takes.
This episode is brought to you by Airbrake. Visit Frictionless error monitoring and performance insight for your app stack.
Follow Joël on Twitter! Welcome him to the show.
Joël Quenneville - DRY is harmful for intermediate devs
Become a Sponsor of The Bike Shed!
Transcript
CHRIS: Thank you. No brown M&M'S. No asking me weird questions. I ask very little.
STEPH: Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Steph Viccari.
CHRIS: I'm Chris Toomey.
JOËL: And I'm Joël Quenneville.
STEPH: And together, we're here to share a bit of what we learned along the way. So, hey, Chris, what's new in your world?
CHRIS: What is new in my world? There is a new friend on the show with us today, Joël, developer extraordinaire, principal developer at thoughtbot, former coach of the Chicago Blackhawks (That one's not true, but it's funny to say.) and friend of the show, many time guest. Joël, so great to see you. How are you today?
JOËL: I'm excited to be joining the show.
CHRIS: Fantastic. So Steph and I shared with the audience in the previous episode that we have decided...we've made the heavy decision that it is time for us to hand over the hosting mantle. But we had yet to discuss exactly where that was going to go. And today, we are happy to share with you the specifics of that, which is that Joël will be taking over the hosting detail. So, Joël, do you have grand plans for where The Bike Shed is going to go from here?
JOËL: Maybe not in grand plans, but I'm definitely already planning content, lining up a few guests. I think the next few weeks are going to be a lot of interviews with some guests, a lot of co-workers at thoughtbot will want to share their stories or some exciting things that they're working on, things they are specialized in.
One thing that I really appreciate at thoughtbot is that we're all pretty full-stack developers. Everybody tends to have a specialization or an area they're really good at. And so when you're ever stuck, and you need advanced Git help, you go to, historically, Chris. If you want some help on security, you go to Mike Burns, et cetera. And so yeah, I'd love to bring in some of them and get to talk a little bit about some of the areas where they're either doing something interesting, or this is just an area where they have deep expertise.
STEPH: I have to say that having you take over as host of the show feels like such a nice continuation, given that you've been involved with The Bike Shed since you were a guest on the show back in 2018. And then, since then, you've been a repeat guest. And even when you're not here, Chris and I still frequently bring up your name and mention some of the talks and the blog posts that you have written.
So I'm super excited for everything that you just said, for all the guests that you're going to bring on the show, and the thoughtbot voices. And I'm looking forward to tuning into future episodes and hearing what happens next.
JOËL: Yeah, this is a really exciting transition for me. I am a long-time fan of the show. I've been a guest a few times. And now, coming on as a host is just taking it to the next level.
CHRIS: Yeah, Joël, I'm also super excited to see the new perspective that you bring to the show. And frankly, to Steph's point, you've been on the show a bunch of times. You've been here in spirit. In fact, there was a tweet that someone sent to us which was "Hey, @joelquen," which is your Twitter handle, "I feel as if I know you and your work after listening to @SViccari and @christoomey. They definitely appreciate you," which was true then and is true now. So I couldn't be happier for you to be taking over this hosting slot.
JOËL: Creating content for developers and sharing the things I've learned, or the things that I've experienced with other people has always been something that's been really important to me. And so, getting a chance to bring that to The Bike Shed is a really exciting opportunity.
My past work has intersected with the show several times, either that's been conference talks or blog posts, or even just conversations we've all had. Steph and I pair almost every day. So there are a lot of good conversations. A lot of conversations that end with me saying, "You should talk about that in The Bike Shed. That's a good topic."
STEPH: You have been an excellent source for topics in terms of you've literally added stuff to our Trello board that we use to manage the show and then yes, and all those conversations that we've had. You're like, "Oh, this will be a good Bike Shed topic." And I'm like, "Hold please," while I go and then add it to our board.
JOËL: The fun of being an employee at thoughtbot is that I have access to the Trello board. And I can just add whatever ideas I have there for you all to talk about. [laughs]
CHRIS: That is the most direct way to send in a listener question is just to write it into the Trello board directly. Skip all the forms, and the Twitter, and the whatnot.
JOËL: Yeah, speaking of topics on our Trello board, let's go out on a really spicy one. I see we have a card about unpopular opinions. Chris, you created this. What is your hot programming take?
CHRIS: This was so long ago, I don't even remember. But this one has interestingly sat on the Trello board for a while. I was like, Steph, let's really lean into it. Let's go out there. What are our extreme takes? And I think we say the stuff that's in our heart most of the time anyway. But we're; also, I don't know, pragmatic, kind of boring up the middle.
Someone recently described my tech choices as like a Subaru. Like the architecture, the way I built it, you know, it's stable. It'll get to where you want to go. It's not going to be too fancy or too flashy. And I was like, you know, actually, humorously, my wife and I just bought a Subaru. So I was like, I guess I can't say no to that.
Anyway, though, I think I have one spicy take, which I have shared on The Bike Shed before. But it is the thing that I will die on this hill. I care about this. It feels like I'm just being persnickety, but I think it matters, which is that the phrase single-page application or the idea of an S-P-A or a SPA, which I've heard some people say it, is just a terrible framework. I am so unhappy with it as a concept.
I think, technically, the implementation of them has often led to some really complicated things, which is why I've spent so much time exploring Inertia, or LiveView or Livewire, or all of the other options that are out there. I think there are some really interesting novel ways. Remix.run is the most recent thing that I've been talking about, which takes a pretty traditional SPA type of build and then makes it behave more like a traditional server-rendered application.
But just the idea single-page application really grinds my gears that that is a thing that we talk about. Because it's the web, we have URLs; these should all be different pages. I don't care if there's one bundle of JavaScript that we send down or that it begins as a single HTML file that we send down, and then we repopulate constantly. There still should be URLs. Those are a honkin' good idea, and we should use more of those. And we shouldn't anchor to a technology...like, no, SPAs, I don't like it. I'm not a fan. So that is my unpopular opinion, I'm pretty sure.
STEPH: I think we have a full episode, too, where we focused a lot on that topic where you shake your fist at the SPAs in the world [laughs] and why you don't like them.
JOËL: I feel like the industry pendulum might be swinging back. I think we've hit peak SPA, and now we're slowly moving back, anecdotally anyway.
CHRIS: That is definitely what I'm seeing more and more of, and I'm very happy for it. Because I think there's some interesting stuff that came out of SPAs and the ideas of like, oh, let's animate, and let's have more continuity and page transitions and things that I think can really enhance the end-user experience. But I think the cost has been too high. It's broken us from some of the norm.
Like, how does the web work? That's a thing that we should talk about. Links, they're awesome. You can link between pages. It's so cool. And we just kind of threw that away. And we're like, div onclick. It'll be fun. Don't worry about it. Screen readers, who cares about those? Doesn't even matter. I care. That's who cares. I'm going to calm down now. I'm fine. It's fine. But yes, I agree. I do think the pendulum is swinging back, and I'm very happy to see that.
JOËL: Long-time listeners of the show will know that I'm a big fan of the Elm language. And for the longest time, I wanted to do a client project at thoughtbot with it. But I agree with you, Chris, that a lot of things shouldn't be SPAs. A lot of things should be just boring Rails apps. And so, every time an opportunity came, I just couldn't justify doing a front-end app. So I would be like, yay, I would love to do Elm here, but this should just be a vanilla Rails app.
And then, one day, we had a project that came in that was actually a single-page app. It was one page where you loaded up a bunch of data streams and then could interact with them and get all these cool visualizations and things. There was no clicking away. There were no other pages. It was just load some data, and you've got a playground. And that was the moment I knew, okay, this is the app I want to do in Elm. And that was my introduction to bringing Elm to colleagues at thoughtbot to work on a project together.
STEPH: You put out the signal kind of like the Batman signal, but you put out the Elm signal calling everybody into the project.
JOËL: [laughs]
CHRIS: You put a small tree on your desk, and everyone came together around it.
JOËL: [laughs]
CHRIS: Also, I want to applaud your pragmatic restraint of I want to use this. This would be fun to use, but it is not the right choice for many particular applications or projects that came through the door. But then you found it. Then you found that magic moment.
To be extra clear, I'm not opposed like; my distinction is an SPA or traditional server-rendered HTML generation on the server...I got redundant in there, but that'll be fine. It's more the bundle of JavaScript that goes down and that there's no routing on the server-side, et cetera, that all logic is pushed to the client-side.
I've harped on about Inertia and my love for that framework over many, many an episode on the show. But I feel like that, and many other solutions that are in that similar space, allow us to have the sort of experiences that are traditionally associated with an SPA but don't give up on the idea of auth being simply managed via a cookie on the server sort of thing. Cookie on the server is a phrase that doesn't really make sense. But y'all get what I'm saying, I hope. If not, assume that I said the right thing. It'll be more fun that way.
JOËL: Steph, I'm curious; what's maybe one of your unpopular opinions or hot takes?
STEPH: I have a couple, and since Chris used a phrase that has now helped anchor me in terms of like the hill that I will die on, I'm now looking through that list to pick the one that I feel like the most passionate about. So looking through that list, I might just have to go a couple. It's hard to really choose.
But the first one is I'm going to say you don't need a side project. I can't tell you how much that frustrates me when people just always say you have to do something on the side. You have to stay up late and code. You have to do coding on the weekends. I feel very strongly that software development is a job, and it doesn't have to be your passion; if it is, that is fabulous.
But it is, at the end of the day, still a job, and you don't need to know three additional languages to be good at your job. And you should be able to focus on learning what makes your day-to-day easier and then learn that during your work hours. So that's something I feel very strongly about.
JOËL: Do you think that's something that is a current reality or something that is aspirational? As in, an employer shouldn't require it, or it is currently possible to have a completely fine career and never have a side project.
STEPH: I think it's very possible currently and aspirational for some teams. I think there are some companies and teams that will turn you down because you don't fit that mold. And I think that's what then puts us in that unpopular opinion category. Because there are enough people that still think that that is an important part of being a software developer.
But I do think that there are still plenty of teams and people that are starting to agree with the idea that it shouldn't be that way and that that is not a requirement for an interview, or for joining the team, or for being a good developer, or for progressing in your skills. So a little bit of both, currently possible and also aspirational.
JOËL: I'm going to throw a question out, and I think this may be its own complete topic. So feel free to tell me that this is not the day to talk about this, but I'm going to put a question out. Recently, there was a really good conversation that happened internally at thoughtbot where one of our newer developers was asking, is it possible to progress our whole career ladder without ever doing any side projects? So just 32 hours of client work, eight hours investment time every week.
And maybe a little bit beyond that, maybe it's technically possible. But it takes an excruciatingly long time. Is it possible to progress in a reasonable amount of time through the career ladder without doing any extra work outside of our standard working hours? What are your thoughts on that for thoughtbot?
STEPH: I think the answer has to be yes. Because I mean, who's creating that ladder that you are climbing? It's going to come down to the company and the managers and the people who are deciding on how you advance, and not everybody has time. So what you're telling me is that if someone can't advance during the normal work hours that they have then...because they have families; they have other priorities in their life; they have other responsibilities, that then they're just stuck? And that feels like an unacceptable answer to me. So my answer is absolutely you can progress during the work hours that you have. And if you can't, then that is a problem for managers and leadership to fix.
CHRIS: I definitely agree with the assertion that you're making, Steph. And I like the ire that you're bringing to this. This is good. This is the sort of fire that we should have in this particular segment. I do think there was an aspect of the question that is subtle and really interesting to me, which is in a reasonable amount of time. And then you mentioned, or it might take an excruciatingly long amount of time.
A thing that I observe about our industry is that it is rather young overall, and the expectations of progression are incredibly rapid. This is sort of my second career. I spent three years as a mechanical engineer working in industry. That was the first thing that I did. And that world looks wildly different.
The idea of achieving principal engineer, which is a little bit more formalized of a concept, but I saw that as 30 years down the road kind of thing, or it may be 20, or something, but a significant chunk of my career. That is something I might achieve towards the end of my career after having put in a lot of time.
And development is just such a young industry. Like, the idea of going to a bootcamp and then two years later being a senior engineer and continuing to progress just ever so rapidly is interesting. I don't want to slow anyone down by any means. And I don't want to say that like, well, when I was over there, it was slower, and so it should be slower here. But I don't think it's realistic, frankly.
And I think some of what is at the heart of this question is like, no, this is an industry where you get in there, and in five years, you have achieved the pinnacle of your career. And then you go retire, and you go to a cabin in the woods, and you never talk to humans or touch a computer again. That's the dream. It's like, well, maybe that's not realistic. And what would it actually look like if we were a little more chill about these sorts of things? That is a question that I have.
STEPH: It's funny that you mentioned that one because that was one that I almost put on my list of unpopular opinions where I think the progression in which we change our titles as developers is silly, [chuckles] is probably the best word that I have for it. Because I agree with you, I don't want to slow people down. And we often change our titles to reflect that, yes, we want more responsibilities. We want more pay, and so that feels like the best way to then achieve those goals.
But it's so rapid in how we expect people to progress to different levels of engineering. I do think it loses a bit of its meaning because then we progress people so quickly through those different roles. Because then senior developer means so much. I mean, are you a senior developer with two years of experience or ten years of experience? Like, you could be in both of those groups. And so, it just loses some of its meaning because of that.
JOËL: It's also hard because years of experience aren't really a good way to compare two developers. I mean, two versus 10 is probably something you can compare very roughly. But five versus 7 or 5 versus 10, someone might be much more experienced or be better at solving problems after five years than somebody else in 10.
CHRIS: I will argue that two years in a consultancy is like five or maybe even ten years in a middle-of-the-road product company that's kind of got its stuff figured out. And just the volume of new and novel that will come at you is quite large. And I strongly recommend working with a lovely company called thoughtbot to get that experience because it'll be a fun time while you're there. And, man, will you learn a lot.
MID-ROLL AD:
Debugging errors can be a developer’s worst nightmare...but it doesn’t have to be. Airbrake is an award-winning error monitoring, performance, and deployment tracking tool created by developers for developers that can actually help you cut your debugging time in half.
So why do developers love Airbrake? Well, it has all of the information that web developers need to monitor their application - including error management, performance insights, and deploy tracking!
Airbrake’s debugging tool catches all your project errors, intelligently groups them, and points you to the issue in the code so you can quickly fix the bug before customers are impacted.
In addition to stellar error monitoring, Airbrake’s lightweight APM enables developers to track the performance and availability of their application through metrics like HTTP requests, response times, error occurrences, and user satisfaction.
Finally, Airbrake Deploy Tracking helps developers track trends, fix bad deploys, and improve code quality.
Since 2008, Airbrake has been a staple in the Ruby community and has grown to cover all major programming languages. Airbrake seamlessly integrates with your favorite apps and includes modern features like single sign-on and SDK-based installation. From testing to production, Airbrake notifiers have your back.
Your time is valuable, so why waste it combing through logs, waiting for user reports, or retrofitting other tools to monitor your application? You literally have nothing to lose. So head on over to airbrake.io/try/bikeshed to create your FREE developer account today!
STEPH: Joël, I have another potentially unpopular opinion I'd love to share. But I'm curious, what's one of yours?
JOËL: So here's a controversial opinion that I have: DRY, Don't Repeat Yourself, is dangerous, I'd say even a harmful rule of thumb for intermediate developers. It's one of our favorite kind of aphorisms, principles that we try to live by as developers. But I think it often does more harm than good at a certain point in your career.
When you start off as a new developer, one of the most common sorts of bugs you'll do is where you duplicate code, and then you change it in one place and don't change it in the other. And they're out of sync, and then your code breaks. And then you discover DRY, Don't Repeat Yourself. And it's amazing because this simple rule fixes 80% of the bugs you were creating. And of course, now there are other types of bugs you find out about. But it's a whole class that gets eliminated by that, and it's wonderful.
But then you get into the intermediate developer, and you start to get clever, and you try to apply this in a lot of places. And you start trying to abstract things that are similar but not the same, and then they start to diverge. And then you've got a mess on your hands. And this happens in application code happens in test code.
Yeah, you end up doing that, prematurely abstracting, and particularly when it's just based on through a simple substring matching. So you're saying this string of 100 characters is identical in two files. We need an abstraction that shares these two when the fact that the two strings might be similar is just coincidental. And so that's where you cause more harm than good. And then eventually, you kind of transcend that, hopefully, and get back to the point where you can maybe apply DRY more judiciously.
Now, DRY is no longer for you about similar characters. It's about similar or actually same concepts because similar is not good enough. And hopefully, you have the discernment to distinguish between similar and same. And when you're not quite sure, maybe you leave them separate to see will they diverge in the next few months?
STEPH: It's almost like you and I are on the same project, and we have felt similar pains in the world.
JOËL: [laughs] I think this is a thing that a lot of developers eventually get to the point where they can do it decently well in production code. But at least when it comes to RSpec code, the Ruby community has just refused to learn this lesson. We're still stuck in that intermediate developer phase where everything's got to be extracted out as shared setup. And I would argue that shared setup on most tests is similar and not same. And the identical thing is if you're just copying two strings of code that look similar in two files and creating an abstraction that really doesn't need to be there.
CHRIS: Friends, I have to tell a truth in this moment. I wrote a let within an RSpec file this week. It happened.
JOËL: [Gasps]
STEPH: This is actually why you're moving off the show, Chris. This right here. [laughs]
CHRIS: I'm getting kicked off the island. I've broken rule number one [chuckles]; let's not. This was...I think it was a reasonable one; at least I couldn't figure out a different way to do it. I was defining a class within an RSpec file, a representative implementation of a subclass. And I tried to do it by just defining a class in line, but RuboCop came along; we recently added RuboCop to the app as well. And RuboCop said, no, no, no, you are leaking a constant. And I said, oh, that's true, RuboCop.
And then, thankfully, the documentation page for that rule had a pointer to what to do instead. And so it ended up with a let. I don't actually think I need to let now that I think about it. You can dynamically define a class within a spec example. So I then, in the rest of the example, started doing that. So I'll probably remove the one let that I actually added. [laughs] But it happened.
JOËL: That honestly seems reasonable to me. I think there are use cases where let can be done correctly. It's just really hard to have the discipline to not stray off that very narrow path of safety. I recently gave a talk at RailsConf about how your test suite is making too many database calls. And most of them are all related to doing way too much during your setup phase.
And one of the reasons I gave that this happens too often is shared setup and let in particular. And I thought that I might get booed off the stage. But in fact, several people came up to me afterwards and told me that I had actually given them a whole new perspective they had never seen, and that was interesting to them.
STEPH: That's awesome. That's so nice that people came up and shared that with you. Yeah, I think one of the areas that I don't know if we highlight enough, but whenever you and I happen to gripe about the use of let or over drying and extracting setup for tests, specifically, is because then we're not talking about the trade-off of then you're coupling all your other tests to that extracted setup.
And so it's not so much that I care that you dried up your test setup, and now the rest of my tests are likely reliant on that extracted shared setup. And then that's where we've introduced a trade-off, and it's a painful trade-off that I have worked through a number of times. So just to add a bit of persnicketiness to our discussion in terms of it's not so much the DRY in the extraction that bothers me, it's then the trade-off of now everything is coupled. And it becomes much harder to then create independent scenarios that are still easy to read and then modify.
JOËL: Because you're coupling two things that are not the same, that want to diverge. And now you're forcing them down a single path. And I think probably the biggest, reddest flag you can get that you've misDRY-ed is where you try to introduce conditionals to your shared extraction. Because the whole point of a shared extraction is that everything is the same. And so once you start introducing branching in there, you know something's gone horribly wrong with your abstraction.
STEPH: Okay, so I think we've established that we've got very strong, maybe popular, unpopular opinions about DRY and especially using DRY in test setup. What's another unpopular opinion that you have, Joël?
JOËL: This one is a stylistic one. But I think that in Ruby, at least, every if should come with an else. You want something to happen when your condition doesn't trigger. I think it generally makes for more readable code and also prevents some implicit nils from getting through. And nil errors are probably at the top of your bug backlog if you were to look at right now (For all of you listeners, I'm pretty sure that's true.), excluding JavaScript.
CHRIS: Someday, we're going to make undefined a function, and it's going to be a great day. This is an interesting one, Joël. I'm inclined to agree with you, but I know that in my code, I don't necessarily follow this adage. So I find it interesting. I would call them intentional nils; I'm sometimes fine with that, or particularly in side effect-y code, you know, if this condition, then do something, otherwise, nothing.
But yeah, it is interesting. The explicitness, the nil, is a big mistake that seems true. You hang out in Elm for long enough, and you don't have one, and then you got to think about stuff harder. But yeah, I don't find myself doing this. So I find it interesting. I conceptually agree with what you're saying, and yet my code tells other stories.
JOËL: So I would argue that Ruby is an expression-oriented language; all methods auto return something as opposed to a statement-driven language like JavaScript, where nothing returns unless you explicitly return it. Ruby is all about those return values. And so you need to cover all branches, and if you don't, Ruby will implicitly have some branches that you don't have there. And so, I prefer to make visible the branching logic that's happening.
STEPH: I also like this one. I think I'm on the same page as Chris, where I like the opinion and this statement. And then also, you'd asked me earlier about whether something is capable now versus aspirational. And this feels like in the aspirational area for me where I agree with it, but I don't necessarily do it. But I think it makes a lot of sense because then it does force you to think about what is the return value? And to be very explicit and say, yep, no, I want a nil here. That's just what I'm going to return.
JOËL: And maybe even think about in that else case maybe you don't always want nil, maybe you'd rather return an empty string, or a null object, or something like that. And forcing you to actually manually type that value in instead of just being like yeah, Ruby knows. It'll put a nil there. It's easy to not think about the error edge cases, which I know is the opposite of how Chris thinks. Chris thinks about all the error edge cases.
CHRIS: My brain has been shifted by experience.
JOËL: One thing that I think this works really well is a stylistic approach that I use where I separate branching code from doing code. So in a particular method, if there is a conditional, then the body of the conditional calls out to another method. It doesn't implement logic there directly. And if a method does a calculation, or does the side effect, or does some kind of work, it's not allowed to have a conditional in it. So an individual method either gets to branch, or it gets to do a thing but not both.
STEPH: Is that so you can quickly see all of the branching that's involved so you can see it at a very high level versus if you have a very large branching in your method and then it's hard to see how many possible return values that you have?
JOËL: Yes. I like it because when you read code, especially when you're reading code that has a conditional in it, typically, you're reading it at a higher level of abstraction. You just want to know what are the possible ways that it can branch, and then what are the paths it can go down? And you probably don't care about all the nitty gritty implementation details that happen at each branch.
And then you might care about one particular branch and decide to go down that path. At that point, you will jump to that method. But you don't need to have all 2 or 3 or 10 branches expanded for you. It keeps the method at a single level of abstraction and also allows each method, in a certain extent, to have a single responsibility. It does one thing. It's either branching between n choices, or it does one thing, but it doesn't try to do multiple things.
So that's less of a hot take opinion, like, everyone should write code that way. That's just a style I've adopted for myself that works really well. But that particularly dovetails nicely with my hot take, which is if should come with an else.
STEPH: I like it.
JOËL: Yeah, so, Steph, do you have another juicy opinion you'd like to share with our listeners?
STEPH: Yeah, I've got one more to share, and this one is going to show my consulting roots. And it's that developers should be included in the design and planning phases, and not just in the execution phase of the work. So that's something that I've seen a number of teams struggle with where they wait until either design is considered completed or perfect or someone else has figured out the way that they want a feature to be built, and then they just essentially throw it over the wall and kick it over to the development team.
And so then it's laid out with very specific criteria. But it's not clear the problem that's actually being solved. And so developers have done a very narrow focus of what they're working on. And you just often end up building the wrong thing when that happens because people don't have the context. They don't know the questions to ask if they do run into some questions regarding the requirements.
And so I strongly advocate that developers shouldn't just pick up tickets and then write code, that they should be part of the planning and the product process as well. Turns out that developers often have really good ideas when it comes to features. And they also have a lot of knowledge about the application and can ask good questions. So why not include them in that process?
JOËL: You mentioned that this is inspired by your experience as a consultant. I've sometimes heard the contrast between the terms contractor versus consultant. Is that a distinction that you make?
STEPH: Yes and no. Yes, because I've heard other people make that distinction, but I personally wouldn't make that distinction. And even for people who are not a contractor or consultant but they're full-time, I still love when people can adopt the mentality of you have the same responsibility of this product and where it's headed and its technical decisions.
And we all should be mindful of the time that we're spending as we're working on something. And I think being a consultant helps you be more mindful in terms of like, oh, I've spent two hours on this problem. I should probably reach out for help. And I feel like people who haven't had an opportunity to be in that mindset don't think that way. But I think it's a really wonderful state to be in all the time just to think through; okay, I've been stuck for an hour, now's the right time that I should reach out for help. Versus spending like a full day on something and then reaching out for help.
So I have heard that distinction, but I personally wouldn't make that distinction. I would advocate that even if you are a consultant, or full-time, or contractor that ideally, you would still be part of those different processes to then help build a valuable product.
JOËL: Steph, I found it really interesting when you introed this idea. It was about developers bringing their ideas to the business and design side of things. But then, when you dug into the idea a little bit more, you kind of flipped it on its head and said that being involved in those meetings helps developers do their job better because now they can more appropriately timebox a feature or decide when they've hit that 80% point that's good enough to ship, and then they need to reprioritize something else. So it sounds like there are advantages to both sides, both the business side and the dev side, from a tighter integration there.
STEPH: Yeah, thanks for calling that out. I think that's an excellent point that I hadn't really even considered as I was just rambling about a strong feeling. But yes, I think it's beneficial to all sides. It's beneficial to developers who are getting the work done. And then I also think it's really beneficial to the product team and design just because that way, everybody essentially has the same context. They're on the same page.
And then you also have more camaraderie that way too in terms of people know the problems that they're trying to solve. And you can have more opinions. And people can surface those ideas versus if you are kept in the dark as to perhaps why a feature is being built or who it's geared towards, then it's more likely that you're not going to be as connected with the rest of the team and be able to provide helpful ideas because you won't have the fuller context to then surface that to the rest of the team.
So this is definitely coming just from all of my experience in the projects that I've been on that the most successful projects include design, and developers, and product management. And they all get together, and they talk about the problems that are being solved. Versus the projects that I've been on where essentially, all of that work is done separately, and then there's just a Trello board or Jira tickets or whatever tool that you're using. And then developers go and pick up tickets.
Because then you often end up having those discussions anyway because developers are then going to have to check in to say, hey, you said this thing. Did you mean this? What exact requirements am I looking for? By siloing that process elsewhere, you end up just duplicating your efforts because that conversation is ideally going to happen anyways.
JOËL: I recently had a conversation with someone who had been promoted to senior developer and was asking me for some advice on how do you be a senior at your job. And this is at a product company. And basically, what you were saying, Steph, is what I recommended. If, as a senior developer, you are just a machine that converts tickets into code, they're not using you to your full potential. And honestly, they're overpaying for what they're getting.
You need to be in those meetings, in those conversations, so that, as you mentioned, you can be that nexus between business and tech and tell them, look, this is your strategic goal. You think this is the technology thing you want to do. Yes, it will solve your problem, but it will take twice as long.
And that is incredibly valuable to the business people because doable and easy, and very similar solution that is near impossible to do in tech are very common. There's a classic xkcd about this situation. And so having someone who knows that nuance and can recommend and say, look, we can do this in two weeks. That will take six months. Or even just talking through trade-offs is incredibly valuable.
And then, as you said, bring that back in your own work, knowing when to say, look, we thought this is going to take two weeks, and it's taking more. We think this is going further. We know that the business goal is to get to here. So I'm going to pause on this and propose a different technical solution that will get us most of the way towards that goal while still respecting the deadlines we're working under.
I might argue that this sort of mindset is not just a senior developer thing. It's valuable at mid-level and junior as well. And I think that as a consulting firm at thoughtbot, that's something that we bring in from the beginning for everyone that we try to build this. But definitely, as you move up into your career, this is going to become more and more important.
CHRIS: Yeah, I'm surprised. I'm actually totally on the opposite side of this one. I fundamentally disagree with...no, I totally agree with everything you're saying and how important these sorts of conversations are. We're actually working on something at Sagewell right now. It's a new, reasonably large integration with an external platform.
And we're very, very intentionally pushing such that product and design are going off and doing some work, and engineering is going off and doing exploratory what do the APIs actually look like? What's the data that we need? What's the object model in this system? What can we get away with not providing? What do we need to provide?
And continually, we're just trying to encourage communication across those different tracks. So design is thinking about different flows and what's the experience a user is going to have. And ideally, getting engineering to review that and say, "Oh, that's going to be easy. That'll be hard. I think we could do that, but I actually have to go look it up and see if that's possible," and vice versa.
Engineering now being in the depths of saying like, "Oh, actually, this has to be done in this way for legal reasons or whatever it is," and then providing that back to design and product to think about how do we structure it? How do we sequence things? What's part of the MVP? And I've been really happy with the nature of that, that back and forth communication.
But it is definitely something that requires intentional work of making sure that we're not just falling into our own silos, but we're coming up for air, having those conversations, passing ideas back and forth, including each other in the conversations. But without question, it will produce a better outcome at the end of the day. So yeah, I actually do, in fact, agree 100%.
STEPH: Yeah, to add on to that just a bit, there is a particular example that comes to mind where I felt the most pain for when developers and product and design aren't in the same room and then discussing the work to be done. And that's essentially where someone ends up building the wrong thing. And it's because someone decided that they knew the best solution for something, but they didn't really collaborate with the rest of the team. They turned that into a ticket.
So then a developer sees that, and then they start implementing, and it's not until later that someone comes along and starts asking questions to say, "Hey, so what problem are we solving?" Or "Why are we adding this code?" And Joël, I think you said it perfectly and that this is something that I do expect of a more senior developer where they have that experience, and they ask those types of questions that then you realize that, oh, we've actually built the wrong thing, or the thing that we're building doesn't solve the problem that we had in mind.
And at that point, you have someone who has invested a week, maybe a couple of weeks into something, so then that feels really terrible to then say, "We actually need to scrap this" or "We need to totally rethink this." So then you start making trade-offs of like, well, maybe we can keep this portion or preserve some of the work that you've done. And so you just end up in a really messy state. And that can be avoided if people are collaborating at an earlier stage of that process.
JOËL: Yes, you and I, Steph, were in a very particular situation where something like this had happened. Some developer had been working on a ticket for a couple of weeks. And it was one of those tickets that just kept growing. The code kept growing, but then the client kept adding new requests and features onto it. And then, at some point, you and I were brought in to help, and the first thing we had to do is like, let's stop and ask what is the problem that is actually being solved here?
And actually got everyone together with the client. And that conversation helped us do a big reset and helped us find a way that was more focused that actually solved the underlying problem, what the client actually wanted rather than what they said they wanted.
I noticed that for most of these unpopular opinions, it sounds like we pretty much all agree with each other. So either we all have a very similar set of unpopular opinions, or maybe these opinions might be a little bit more mainstream than we give them credit for. I find that oftentimes, at least on Twitter, when people tag things as "unpopular opinion" in quotes, they may be a little bit more popular than people give credit for.
CHRIS: I feel like the RSpec one is unpopular. And also, have you asked Steph about Pop-Tarts?
JOËL: [laughs]
CHRIS: Because we are capable of having sincerely unpopular opinions.
JOËL: Let's save that for the next episode. And on that note, shall we wrap up?
CHRIS: The show notes for this episode can be found at bikeshed.fm.
STEPH: This show is produced and edited by Mandy Moore.
CHRIS: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or even a review on iTunes, as it really helps other folks find the show.
STEPH: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed or reach me on Twitter @SViccari.
CHRIS: And I'm @christoomey.
STEPH: Or you can reach us at hosts@bikeshed.fm via email.
CHRIS: Thanks so much for listening to The Bike Shed, and we'll see you next week.
ALL: Byeeeeeeeeee!!!!!!
ANNOUNCER: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.Sponsored By:Airbrake: Deploy fearlessly and fix bugs faster with Airbrake Error & Performance Monitoring. Airbrake notifiers are available for all major programming languages and frameworks, and install in minutes, with an open-source SDK-based install and near-zero technical debt. Spend less time tracking down bugs and more time developing. Visit Frictionless error monitoring and performance insight for your app stack.Support The Bike Shed


